Version Description
- Fix - Now you can choose how many duplicates to see in the interface.
- Tested with WordPress 6.0.
- Updated language file for translations.
Download this release
Release Info
Developer | lkoudal |
Plugin | Delete Duplicate Posts |
Version | 4.7.7 |
Comparing to | |
See all releases |
Code changes from version 4.7.6 to 4.7.7
- css/delete-duplicate-posts-min.css +2 -3
- css/delete-duplicate-posts.css +2 -3
- delete-duplicate-posts.php +14 -16
- freemius/includes/class-fs-api.php +663 -663
- freemius/includes/class-fs-options.php +430 -430
- freemius/includes/class-fs-plugin-updater.php +1561 -1561
- freemius/includes/class-fs-storage.php +531 -531
- freemius/includes/fs-core-functions.php +1415 -1415
- freemius/includes/fs-essential-functions.php +499 -499
- freemius/includes/fs-plugin-info-dialog.php +1644 -1644
- freemius/includes/i18n.php +605 -605
- freemius/includes/managers/class-fs-plugin-manager.php +219 -219
- freemius/templates/account.php +1097 -1097
- freemius/templates/account/partials/site.php +351 -351
- freemius/templates/add-ons.php +501 -501
- freemius/templates/connect.php +1037 -1037
- freemius/templates/forms/data-debug-mode.php +212 -212
- freemius/templates/forms/license-activation.php +581 -869
css/delete-duplicate-posts-min.css
CHANGED
@@ -204,11 +204,10 @@
|
|
204 |
}
|
205 |
|
206 |
#sidebar-container .sidebarrow img.logo {
|
207 |
-
|
208 |
-
width: 50%;
|
209 |
margin-bottom: 10px;
|
210 |
display: block;
|
211 |
-
|
|
|
212 |
}
|
213 |
|
214 |
#log {
|
204 |
}
|
205 |
|
206 |
#sidebar-container .sidebarrow img.logo {
|
|
|
|
|
207 |
margin-bottom: 10px;
|
208 |
display: block;
|
209 |
+
float: left;
|
210 |
+
width: 100%;
|
211 |
}
|
212 |
|
213 |
#log {
|
css/delete-duplicate-posts.css
CHANGED
@@ -204,11 +204,10 @@
|
|
204 |
}
|
205 |
|
206 |
#sidebar-container .sidebarrow img.logo {
|
207 |
-
|
208 |
-
width: 50%;
|
209 |
margin-bottom: 10px;
|
210 |
display: block;
|
211 |
-
|
|
|
212 |
}
|
213 |
|
214 |
#log {
|
204 |
}
|
205 |
|
206 |
#sidebar-container .sidebarrow img.logo {
|
|
|
|
|
207 |
margin-bottom: 10px;
|
208 |
display: block;
|
209 |
+
float: left;
|
210 |
+
width: 100%;
|
211 |
}
|
212 |
|
213 |
#log {
|
delete-duplicate-posts.php
CHANGED
@@ -5,11 +5,11 @@ Plugin Name: Delete Duplicate Posts
|
|
5 |
Plugin Script: delete-duplicate-posts.php
|
6 |
Plugin URI: https://cleverplugins.com
|
7 |
Description: Remove duplicate blogposts on your blog! Searches and removes duplicate posts and their post meta tags. You can delete posts, pages and other Custom Post Types enabled on your website.
|
8 |
-
Version: 4.7.
|
9 |
Author: cleverplugins.com
|
10 |
Author URI: https://cleverplugins.com
|
11 |
Min WP Version: 4.7
|
12 |
-
Max WP Version:
|
13 |
Text Domain: delete-duplicate-posts
|
14 |
Domain Path: /languages
|
15 |
*/
|
@@ -521,13 +521,14 @@ if ( !class_exists( 'Delete_Duplicate_Posts' ) ) {
|
|
521 |
global $wpdb ;
|
522 |
$table_name = $wpdb->prefix . 'posts';
|
523 |
$resultslimit = $options['ddp_resultslimit'];
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
|
|
531 |
$ddp_pts_arr = $options['ddp_pts'];
|
532 |
|
533 |
if ( isset( $ddp_pts_arr ) && is_array( $ddp_pts_arr ) ) {
|
@@ -571,7 +572,7 @@ if ( !class_exists( 'Delete_Duplicate_Posts' ) ) {
|
|
571 |
}
|
572 |
$thisquery = "SELECT t1.ID, t1.post_title, t1.post_type, t1.post_status, save_this_post_id\n\t\t\t\t\t\t\t\t\t\t\t\t\tFROM {$table_name} AS t1 INNER JOIN (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT post_title, " . $minmax . " AS save_this_post_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM {$table_name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE post_type IN (" . $ddp_pts . ')
|
573 |
AND post_status IN (' . $post_stati . ')
|
574 |
-
GROUP BY post_title HAVING COUNT(*)>1
|
575 |
) AS t2 ON t1.post_title = t2.post_title
|
576 |
AND post_status IN (' . $post_stati . ')
|
577 |
ORDER BY t1.post_title, t1.post_date DESC';
|
@@ -1363,8 +1364,7 @@ if ( !class_exists( 'Delete_Duplicate_Posts' ) ) {
|
|
1363 |
foreach ( $post_types as $pt ) {
|
1364 |
$checked = array_search( $pt, $checked_post_types, true );
|
1365 |
?>
|
1366 |
-
<li
|
1367 |
-
<input type="checkbox" name="ddp_pts[]" id="ddp_pt-<?php
|
1368 |
echo esc_attr( $step ) ;
|
1369 |
?>" value="<?php
|
1370 |
echo esc_html( $pt ) ;
|
@@ -1373,8 +1373,7 @@ if ( !class_exists( 'Delete_Duplicate_Posts' ) ) {
|
|
1373 |
if ( false !== $checked ) {
|
1374 |
echo ' checked' ;
|
1375 |
}
|
1376 |
-
|
1377 |
-
/>
|
1378 |
<label for="ddp_pt-<?php
|
1379 |
echo esc_attr( $step ) ;
|
1380 |
?>"><?php
|
@@ -1389,8 +1388,7 @@ if ( !class_exists( 'Delete_Duplicate_Posts' ) ) {
|
|
1389 |
}
|
1390 |
// translators: Total number of deleted duplicates
|
1391 |
echo '<small>' . sprintf( esc_html__( '(%s total found)', 'delete-duplicate-posts' ), esc_html( number_format_i18n( $othercount ) ) ) . '</small>' ;
|
1392 |
-
|
1393 |
-
</li>
|
1394 |
<?php
|
1395 |
$step++;
|
1396 |
}
|
5 |
Plugin Script: delete-duplicate-posts.php
|
6 |
Plugin URI: https://cleverplugins.com
|
7 |
Description: Remove duplicate blogposts on your blog! Searches and removes duplicate posts and their post meta tags. You can delete posts, pages and other Custom Post Types enabled on your website.
|
8 |
+
Version: 4.7.7
|
9 |
Author: cleverplugins.com
|
10 |
Author URI: https://cleverplugins.com
|
11 |
Min WP Version: 4.7
|
12 |
+
Max WP Version: 6.0
|
13 |
Text Domain: delete-duplicate-posts
|
14 |
Domain Path: /languages
|
15 |
*/
|
521 |
global $wpdb ;
|
522 |
$table_name = $wpdb->prefix . 'posts';
|
523 |
$resultslimit = $options['ddp_resultslimit'];
|
524 |
+
$viewlimit = $resultslimit;
|
525 |
+
/*
|
526 |
+
if ( 101 < $resultslimit ) {
|
527 |
+
$viewlimit = $resultslimit;
|
528 |
+
} else {
|
529 |
+
$viewlimit = 50;
|
530 |
+
}
|
531 |
+
*/
|
532 |
$ddp_pts_arr = $options['ddp_pts'];
|
533 |
|
534 |
if ( isset( $ddp_pts_arr ) && is_array( $ddp_pts_arr ) ) {
|
572 |
}
|
573 |
$thisquery = "SELECT t1.ID, t1.post_title, t1.post_type, t1.post_status, save_this_post_id\n\t\t\t\t\t\t\t\t\t\t\t\t\tFROM {$table_name} AS t1 INNER JOIN (\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tSELECT post_title, " . $minmax . " AS save_this_post_id\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tFROM {$table_name}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tWHERE post_type IN (" . $ddp_pts . ')
|
574 |
AND post_status IN (' . $post_stati . ')
|
575 |
+
GROUP BY post_title HAVING COUNT(*)>1 ' . $resultsoutput . '
|
576 |
) AS t2 ON t1.post_title = t2.post_title
|
577 |
AND post_status IN (' . $post_stati . ')
|
578 |
ORDER BY t1.post_title, t1.post_date DESC';
|
1364 |
foreach ( $post_types as $pt ) {
|
1365 |
$checked = array_search( $pt, $checked_post_types, true );
|
1366 |
?>
|
1367 |
+
<li><input type="checkbox" name="ddp_pts[]" id="ddp_pt-<?php
|
|
|
1368 |
echo esc_attr( $step ) ;
|
1369 |
?>" value="<?php
|
1370 |
echo esc_html( $pt ) ;
|
1373 |
if ( false !== $checked ) {
|
1374 |
echo ' checked' ;
|
1375 |
}
|
1376 |
+
?>/>
|
|
|
1377 |
<label for="ddp_pt-<?php
|
1378 |
echo esc_attr( $step ) ;
|
1379 |
?>"><?php
|
1388 |
}
|
1389 |
// translators: Total number of deleted duplicates
|
1390 |
echo '<small>' . sprintf( esc_html__( '(%s total found)', 'delete-duplicate-posts' ), esc_html( number_format_i18n( $othercount ) ) ) . '</small>' ;
|
1391 |
+
?></li>
|
|
|
1392 |
<?php
|
1393 |
$step++;
|
1394 |
}
|
freemius/includes/class-fs-api.php
CHANGED
@@ -1,664 +1,664 @@
|
|
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 1.0.4
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Class FS_Api
|
15 |
-
*
|
16 |
-
* Wraps Freemius API SDK to handle:
|
17 |
-
* 1. Clock sync.
|
18 |
-
* 2. Fallback to HTTP when HTTPS fails.
|
19 |
-
* 3. Adds caching layer to GET requests.
|
20 |
-
* 4. Adds consistency for failed requests by using last cached version.
|
21 |
-
*/
|
22 |
-
class FS_Api {
|
23 |
-
/**
|
24 |
-
* @var FS_Api[]
|
25 |
-
*/
|
26 |
-
private static $_instances = array();
|
27 |
-
|
28 |
-
/**
|
29 |
-
* @var FS_Option_Manager Freemius options, options-manager.
|
30 |
-
*/
|
31 |
-
private static $_options;
|
32 |
-
|
33 |
-
/**
|
34 |
-
* @var FS_Cache_Manager API Caching layer
|
35 |
-
*/
|
36 |
-
private static $_cache;
|
37 |
-
|
38 |
-
/**
|
39 |
-
* @var int Clock diff in seconds between current server to API server.
|
40 |
-
*/
|
41 |
-
private static $_clock_diff;
|
42 |
-
|
43 |
-
/**
|
44 |
-
* @var Freemius_Api_WordPress
|
45 |
-
*/
|
46 |
-
private $_api;
|
47 |
-
|
48 |
-
/**
|
49 |
-
* @var string
|
50 |
-
*/
|
51 |
-
private $_slug;
|
52 |
-
|
53 |
-
/**
|
54 |
-
* @var FS_Logger
|
55 |
-
* @since 1.0.4
|
56 |
-
*/
|
57 |
-
private $_logger;
|
58 |
-
|
59 |
-
/**
|
60 |
-
* @author Leo Fajardo (@leorw)
|
61 |
-
* @since 2.3.0
|
62 |
-
*
|
63 |
-
* @var string
|
64 |
-
*/
|
65 |
-
private $_sdk_version;
|
66 |
-
|
67 |
-
/**
|
68 |
-
* @param string $slug
|
69 |
-
* @param string $scope 'app', 'developer', 'user' or 'install'.
|
70 |
-
* @param number $id Element's id.
|
71 |
-
* @param string $public_key Public key.
|
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 |
-
*/
|
78 |
-
static function instance(
|
79 |
-
$slug,
|
80 |
-
$scope,
|
81 |
-
$id,
|
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 ];
|
96 |
-
}
|
97 |
-
|
98 |
-
private static function _init() {
|
99 |
-
if ( isset( self::$_options ) ) {
|
100 |
-
return;
|
101 |
-
}
|
102 |
-
|
103 |
-
if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
|
104 |
-
require_once WP_FS__DIR_SDK . '/FreemiusWordPress.php';
|
105 |
-
}
|
106 |
-
|
107 |
-
self::$_options = FS_Option_Manager::get_manager( WP_FS__OPTIONS_OPTION_NAME, true, true );
|
108 |
-
self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
|
109 |
-
|
110 |
-
self::$_clock_diff = self::$_options->get_option( 'api_clock_diff', 0 );
|
111 |
-
Freemius_Api_WordPress::SetClockDiff( self::$_clock_diff );
|
112 |
-
|
113 |
-
if ( self::$_options->get_option( 'api_force_http', false ) ) {
|
114 |
-
Freemius_Api_WordPress::SetHttp();
|
115 |
-
}
|
116 |
-
}
|
117 |
-
|
118 |
-
/**
|
119 |
-
* @param string $slug
|
120 |
-
* @param string $scope 'app', 'developer', 'user' or 'install'.
|
121 |
-
* @param number $id Element's id.
|
122 |
-
* @param string $public_key Public key.
|
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,
|
129 |
-
$scope,
|
130 |
-
$id,
|
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 |
-
|
143 |
-
/**
|
144 |
-
* Find clock diff between server and API server, and store the diff locally.
|
145 |
-
*
|
146 |
-
* @param bool|int $diff
|
147 |
-
*
|
148 |
-
* @return bool|int False if clock diff didn't change, otherwise returns the clock diff in seconds.
|
149 |
-
*/
|
150 |
-
private function _sync_clock_diff( $diff = false ) {
|
151 |
-
$this->_logger->entrance();
|
152 |
-
|
153 |
-
// Sync clock and store.
|
154 |
-
$new_clock_diff = ( false === $diff ) ?
|
155 |
-
Freemius_Api_WordPress::FindClockDiff() :
|
156 |
-
$diff;
|
157 |
-
|
158 |
-
if ( $new_clock_diff === self::$_clock_diff ) {
|
159 |
-
return false;
|
160 |
-
}
|
161 |
-
|
162 |
-
self::$_clock_diff = $new_clock_diff;
|
163 |
-
|
164 |
-
// Update API clock's diff.
|
165 |
-
Freemius_Api_WordPress::SetClockDiff( self::$_clock_diff );
|
166 |
-
|
167 |
-
// Store new clock diff in storage.
|
168 |
-
self::$_options->set_option( 'api_clock_diff', self::$_clock_diff, true );
|
169 |
-
|
170 |
-
return $new_clock_diff;
|
171 |
-
}
|
172 |
-
|
173 |
-
/**
|
174 |
-
* Override API call to enable retry with servers' clock auto sync method.
|
175 |
-
*
|
176 |
-
* @param string $path
|
177 |
-
* @param string $method
|
178 |
-
* @param array $params
|
179 |
-
* @param bool $retry Is in retry or first call attempt.
|
180 |
-
*
|
181 |
-
* @return array|mixed|string|void
|
182 |
-
*/
|
183 |
-
private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
|
184 |
-
$this->_logger->entrance( $method . ':' . $path );
|
185 |
-
|
186 |
-
if ( self::is_temporary_down() ) {
|
187 |
-
$result = $this->get_temporary_unavailable_error();
|
188 |
-
} else {
|
189 |
-
/**
|
190 |
-
* @since 2.3.0 Include the SDK version with all API requests that going through the API manager. IMPORTANT: Only pass the SDK version if the caller didn't include it yet.
|
191 |
-
*/
|
192 |
-
if ( ! empty( $this->_sdk_version ) ) {
|
193 |
-
if ( false === strpos( $path, 'sdk_version=' ) &&
|
194 |
-
! isset( $params['sdk_version'] )
|
195 |
-
) {
|
196 |
-
// Always add the sdk_version param in the querystring. DO NOT INCLUDE IT IN THE BODY PARAMS, OTHERWISE, IT MAY LEAD TO AN UNEXPECTED PARAMS PARSING IN CASES WHERE THE $params IS A REGULAR NON-ASSOCIATIVE ARRAY.
|
197 |
-
$path = add_query_arg( 'sdk_version', $this->_sdk_version, $path );
|
198 |
-
}
|
199 |
-
}
|
200 |
-
|
201 |
-
$result = $this->_api->Api( $path, $method, $params );
|
202 |
-
|
203 |
-
if ( null !== $result &&
|
204 |
-
isset( $result->error ) &&
|
205 |
-
isset( $result->error->code ) &&
|
206 |
-
'request_expired' === $result->error->code
|
207 |
-
) {
|
208 |
-
if ( ! $retry ) {
|
209 |
-
$diff = isset( $result->error->timestamp ) ?
|
210 |
-
( time() - strtotime( $result->error->timestamp ) ) :
|
211 |
-
false;
|
212 |
-
|
213 |
-
// Try to sync clock diff.
|
214 |
-
if ( false !== $this->_sync_clock_diff( $diff ) ) {
|
215 |
-
// Retry call with new synced clock.
|
216 |
-
return $this->_call( $path, $method, $params, true );
|
217 |
-
}
|
218 |
-
}
|
219 |
-
}
|
220 |
-
}
|
221 |
-
|
222 |
-
if ( $this->_logger->is_on() && self::is_api_error( $result ) ) {
|
223 |
-
// Log API errors.
|
224 |
-
$this->_logger->api_error( $result );
|
225 |
-
}
|
226 |
-
|
227 |
-
return $result;
|
228 |
-
}
|
229 |
-
|
230 |
-
/**
|
231 |
-
* Override API call to wrap it in servers' clock sync method.
|
232 |
-
*
|
233 |
-
* @param string $path
|
234 |
-
* @param string $method
|
235 |
-
* @param array $params
|
236 |
-
*
|
237 |
-
* @return array|mixed|string|void
|
238 |
-
* @throws Freemius_Exception
|
239 |
-
*/
|
240 |
-
function call( $path, $method = 'GET', $params = array() ) {
|
241 |
-
return $this->_call( $path, $method, $params );
|
242 |
-
}
|
243 |
-
|
244 |
-
/**
|
245 |
-
* Get API request URL signed via query string.
|
246 |
-
*
|
247 |
-
* @param string $path
|
248 |
-
*
|
249 |
-
* @return string
|
250 |
-
*/
|
251 |
-
function get_signed_url( $path ) {
|
252 |
-
return $this->_api->GetSignedUrl( $path );
|
253 |
-
}
|
254 |
-
|
255 |
-
/**
|
256 |
-
* @param string $path
|
257 |
-
* @param bool $flush
|
258 |
-
* @param int $expiration (optional) Time until expiration in seconds from now, defaults to 24 hours
|
259 |
-
*
|
260 |
-
* @return stdClass|mixed
|
261 |
-
*/
|
262 |
-
function get( $path = '/', $flush = false, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
|
263 |
-
$this->_logger->entrance( $path );
|
264 |
-
|
265 |
-
$cache_key = $this->get_cache_key( $path );
|
266 |
-
|
267 |
-
// Always flush during development.
|
268 |
-
if ( WP_FS__DEV_MODE || $this->_api->IsSandbox() ) {
|
269 |
-
$flush = true;
|
270 |
-
}
|
271 |
-
|
272 |
-
$cached_result = self::$_cache->get( $cache_key );
|
273 |
-
|
274 |
-
if ( $flush || ! self::$_cache->has_valid( $cache_key, $expiration ) ) {
|
275 |
-
$result = $this->call( $path );
|
276 |
-
|
277 |
-
if ( ! is_object( $result ) || isset( $result->error ) ) {
|
278 |
-
// Api returned an error.
|
279 |
-
if ( is_object( $cached_result ) &&
|
280 |
-
! isset( $cached_result->error )
|
281 |
-
) {
|
282 |
-
// If there was an error during a newer data fetch,
|
283 |
-
// fallback to older data version.
|
284 |
-
$result = $cached_result;
|
285 |
-
|
286 |
-
if ( $this->_logger->is_on() ) {
|
287 |
-
$this->_logger->warn( 'Fallback to cached API result: ' . var_export( $cached_result, true ) );
|
288 |
-
}
|
289 |
-
} else {
|
290 |
-
if ( is_object( $result ) && isset( $result->error->http ) && 404 == $result->error->http ) {
|
291 |
-
/**
|
292 |
-
* If the response code is 404, cache the result for half of the `$expiration`.
|
293 |
-
*
|
294 |
-
* @author Leo Fajardo (@leorw)
|
295 |
-
* @since 2.2.4
|
296 |
-
*/
|
297 |
-
$expiration /= 2;
|
298 |
-
} else {
|
299 |
-
// If no older data version and the response code is not 404, return result without
|
300 |
-
// caching the error.
|
301 |
-
return $result;
|
302 |
-
}
|
303 |
-
}
|
304 |
-
}
|
305 |
-
|
306 |
-
self::$_cache->set( $cache_key, $result, $expiration );
|
307 |
-
|
308 |
-
$cached_result = $result;
|
309 |
-
} else {
|
310 |
-
$this->_logger->log( 'Using cached API result.' );
|
311 |
-
}
|
312 |
-
|
313 |
-
return $cached_result;
|
314 |
-
}
|
315 |
-
|
316 |
-
/**
|
317 |
-
* Check if there's a cached version of the API request.
|
318 |
-
*
|
319 |
-
* @author Vova Feldman (@svovaf)
|
320 |
-
* @since 1.2.1
|
321 |
-
*
|
322 |
-
* @param string $path
|
323 |
-
* @param string $method
|
324 |
-
* @param array $params
|
325 |
-
*
|
326 |
-
* @return bool
|
327 |
-
*/
|
328 |
-
function is_cached( $path, $method = 'GET', $params = array() ) {
|
329 |
-
$cache_key = $this->get_cache_key( $path, $method, $params );
|
330 |
-
|
331 |
-
return self::$_cache->has_valid( $cache_key );
|
332 |
-
}
|
333 |
-
|
334 |
-
/**
|
335 |
-
* Invalidate a cached version of the API request.
|
336 |
-
*
|
337 |
-
* @author Vova Feldman (@svovaf)
|
338 |
-
* @since 1.2.1.5
|
339 |
-
*
|
340 |
-
* @param string $path
|
341 |
-
* @param string $method
|
342 |
-
* @param array $params
|
343 |
-
*/
|
344 |
-
function purge_cache( $path, $method = 'GET', $params = array() ) {
|
345 |
-
$this->_logger->entrance( "{$method}:{$path}" );
|
346 |
-
|
347 |
-
$cache_key = $this->get_cache_key( $path, $method, $params );
|
348 |
-
|
349 |
-
self::$_cache->purge( $cache_key );
|
350 |
-
}
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Invalidate a cached version of the API request.
|
354 |
-
*
|
355 |
-
* @author Vova Feldman (@svovaf)
|
356 |
-
* @since 2.0.0
|
357 |
-
*
|
358 |
-
* @param string $path
|
359 |
-
* @param int $expiration
|
360 |
-
* @param string $method
|
361 |
-
* @param array $params
|
362 |
-
*/
|
363 |
-
function update_cache_expiration( $path, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $method = 'GET', $params = array() ) {
|
364 |
-
$this->_logger->entrance( "{$method}:{$path}:{$expiration}" );
|
365 |
-
|
366 |
-
$cache_key = $this->get_cache_key( $path, $method, $params );
|
367 |
-
|
368 |
-
self::$_cache->update_expiration( $cache_key, $expiration );
|
369 |
-
}
|
370 |
-
|
371 |
-
/**
|
372 |
-
* @param string $path
|
373 |
-
* @param string $method
|
374 |
-
* @param array $params
|
375 |
-
*
|
376 |
-
* @return string
|
377 |
-
* @throws \Freemius_Exception
|
378 |
-
*/
|
379 |
-
private function get_cache_key( $path, $method = 'GET', $params = array() ) {
|
380 |
-
$canonized = $this->_api->CanonizePath( $path );
|
381 |
-
// $exploded = explode('/', $canonized);
|
382 |
-
// return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
|
383 |
-
return strtolower( $method . ':' . $canonized ) . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
|
384 |
-
}
|
385 |
-
|
386 |
-
/**
|
387 |
-
* Test API connectivity.
|
388 |
-
*
|
389 |
-
* @author Vova Feldman (@svovaf)
|
390 |
-
* @since 1.0.9 If fails, try to fallback to HTTP.
|
391 |
-
* @since 1.1.6 Added a 5-min caching mechanism, to prevent from overloading the server if the API if
|
392 |
-
* temporary down.
|
393 |
-
*
|
394 |
-
* @return bool True if successful connectivity to the API.
|
395 |
-
*/
|
396 |
-
static function test() {
|
397 |
-
self::_init();
|
398 |
-
|
399 |
-
$cache_key = 'ping_test';
|
400 |
-
|
401 |
-
$test = self::$_cache->get_valid( $cache_key, null );
|
402 |
-
|
403 |
-
if ( is_null( $test ) ) {
|
404 |
-
$test = Freemius_Api_WordPress::Test();
|
405 |
-
|
406 |
-
if ( false === $test && Freemius_Api_WordPress::IsHttps() ) {
|
407 |
-
// Fallback to HTTP, since HTTPS fails.
|
408 |
-
Freemius_Api_WordPress::SetHttp();
|
409 |
-
|
410 |
-
self::$_options->set_option( 'api_force_http', true, true );
|
411 |
-
|
412 |
-
$test = Freemius_Api_WordPress::Test();
|
413 |
-
|
414 |
-
if ( false === $test ) {
|
415 |
-
/**
|
416 |
-
* API connectivity test fail also in HTTP request, therefore,
|
417 |
-
* fallback to HTTPS to keep connection secure.
|
418 |
-
*
|
419 |
-
* @since 1.1.6
|
420 |
-
*/
|
421 |
-
self::$_options->set_option( 'api_force_http', false, true );
|
422 |
-
}
|
423 |
-
}
|
424 |
-
|
425 |
-
self::$_cache->set( $cache_key, $test, WP_FS__TIME_5_MIN_IN_SEC );
|
426 |
-
}
|
427 |
-
|
428 |
-
return $test;
|
429 |
-
}
|
430 |
-
|
431 |
-
/**
|
432 |
-
* Check if API is temporary down.
|
433 |
-
*
|
434 |
-
* @author Vova Feldman (@svovaf)
|
435 |
-
* @since 1.1.6
|
436 |
-
*
|
437 |
-
* @return bool
|
438 |
-
*/
|
439 |
-
static function is_temporary_down() {
|
440 |
-
self::_init();
|
441 |
-
|
442 |
-
$test = self::$_cache->get_valid( 'ping_test', null );
|
443 |
-
|
444 |
-
return ( false === $test );
|
445 |
-
}
|
446 |
-
|
447 |
-
/**
|
448 |
-
* @author Vova Feldman (@svovaf)
|
449 |
-
* @since 1.1.6
|
450 |
-
*
|
451 |
-
* @return object
|
452 |
-
*/
|
453 |
-
private function get_temporary_unavailable_error() {
|
454 |
-
return (object) array(
|
455 |
-
'error' => (object) array(
|
456 |
-
'type' => 'TemporaryUnavailable',
|
457 |
-
'message' => 'API is temporary unavailable, please retry in ' . ( self::$_cache->get_record_expiration( 'ping_test' ) - WP_FS__SCRIPT_START_TIME ) . ' sec.',
|
458 |
-
'code' => 'temporary_unavailable',
|
459 |
-
'http' => 503
|
460 |
-
)
|
461 |
-
);
|
462 |
-
}
|
463 |
-
|
464 |
-
/**
|
465 |
-
* Ping API for connectivity test, and return result object.
|
466 |
-
*
|
467 |
-
* @author Vova Feldman (@svovaf)
|
468 |
-
* @since 1.0.9
|
469 |
-
*
|
470 |
-
* @param null|string $unique_anonymous_id
|
471 |
-
* @param array $params
|
472 |
-
*
|
473 |
-
* @return object
|
474 |
-
*/
|
475 |
-
function ping( $unique_anonymous_id = null, $params = array() ) {
|
476 |
-
$this->_logger->entrance();
|
477 |
-
|
478 |
-
if ( self::is_temporary_down() ) {
|
479 |
-
return $this->get_temporary_unavailable_error();
|
480 |
-
}
|
481 |
-
|
482 |
-
$pong = is_null( $unique_anonymous_id ) ?
|
483 |
-
Freemius_Api_WordPress::Ping() :
|
484 |
-
$this->_call( 'ping.json?' . http_build_query( array_merge(
|
485 |
-
array( 'uid' => $unique_anonymous_id ),
|
486 |
-
$params
|
487 |
-
) ) );
|
488 |
-
|
489 |
-
if ( $this->is_valid_ping( $pong ) ) {
|
490 |
-
return $pong;
|
491 |
-
}
|
492 |
-
|
493 |
-
if ( self::should_try_with_http( $pong ) ) {
|
494 |
-
// Fallback to HTTP, since HTTPS fails.
|
495 |
-
Freemius_Api_WordPress::SetHttp();
|
496 |
-
|
497 |
-
self::$_options->set_option( 'api_force_http', true, true );
|
498 |
-
|
499 |
-
$pong = is_null( $unique_anonymous_id ) ?
|
500 |
-
Freemius_Api_WordPress::Ping() :
|
501 |
-
$this->_call( 'ping.json?' . http_build_query( array_merge(
|
502 |
-
array( 'uid' => $unique_anonymous_id ),
|
503 |
-
$params
|
504 |
-
) ) );
|
505 |
-
|
506 |
-
if ( ! $this->is_valid_ping( $pong ) ) {
|
507 |
-
self::$_options->set_option( 'api_force_http', false, true );
|
508 |
-
}
|
509 |
-
}
|
510 |
-
|
511 |
-
return $pong;
|
512 |
-
}
|
513 |
-
|
514 |
-
/**
|
515 |
-
* Check if based on the API result we should try
|
516 |
-
* to re-run the same request with HTTP instead of HTTPS.
|
517 |
-
*
|
518 |
-
* @author Vova Feldman (@svovaf)
|
519 |
-
* @since 1.1.6
|
520 |
-
*
|
521 |
-
* @param $result
|
522 |
-
*
|
523 |
-
* @return bool
|
524 |
-
*/
|
525 |
-
private static function should_try_with_http( $result ) {
|
526 |
-
if ( ! Freemius_Api_WordPress::IsHttps() ) {
|
527 |
-
return false;
|
528 |
-
}
|
529 |
-
|
530 |
-
return ( ! is_object( $result ) ||
|
531 |
-
! isset( $result->error ) ||
|
532 |
-
! isset( $result->error->code ) ||
|
533 |
-
! in_array( $result->error->code, array(
|
534 |
-
'curl_missing',
|
535 |
-
'cloudflare_ddos_protection',
|
536 |
-
'maintenance_mode',
|
537 |
-
'squid_cache_block',
|
538 |
-
'too_many_requests',
|
539 |
-
) ) );
|
540 |
-
|
541 |
-
}
|
542 |
-
|
543 |
-
/**
|
544 |
-
* Check if valid ping request result.
|
545 |
-
*
|
546 |
-
* @author Vova Feldman (@svovaf)
|
547 |
-
* @since 1.1.1
|
548 |
-
*
|
549 |
-
* @param mixed $pong
|
550 |
-
*
|
551 |
-
* @return bool
|
552 |
-
*/
|
553 |
-
function is_valid_ping( $pong ) {
|
554 |
-
return Freemius_Api_WordPress::Test( $pong );
|
555 |
-
}
|
556 |
-
|
557 |
-
function get_url( $path = '' ) {
|
558 |
-
return Freemius_Api_WordPress::GetUrl( $path, $this->_api->IsSandbox() );
|
559 |
-
}
|
560 |
-
|
561 |
-
/**
|
562 |
-
* Clear API cache.
|
563 |
-
*
|
564 |
-
* @author Vova Feldman (@svovaf)
|
565 |
-
* @since 1.0.9
|
566 |
-
*/
|
567 |
-
static function clear_cache() {
|
568 |
-
self::_init();
|
569 |
-
|
570 |
-
self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
|
571 |
-
self::$_cache->clear();
|
572 |
-
}
|
573 |
-
|
574 |
-
#----------------------------------------------------------------------------------
|
575 |
-
#region Error Handling
|
576 |
-
#----------------------------------------------------------------------------------
|
577 |
-
|
578 |
-
/**
|
579 |
-
* @author Vova Feldman (@svovaf)
|
580 |
-
* @since 1.2.1.5
|
581 |
-
*
|
582 |
-
* @param mixed $result
|
583 |
-
*
|
584 |
-
* @return bool Is API result contains an error.
|
585 |
-
*/
|
586 |
-
static function is_api_error( $result ) {
|
587 |
-
return ( is_object( $result ) && isset( $result->error ) ) ||
|
588 |
-
is_string( $result );
|
589 |
-
}
|
590 |
-
|
591 |
-
/**
|
592 |
-
* @author Vova Feldman (@svovaf)
|
593 |
-
* @since 2.0.0
|
594 |
-
*
|
595 |
-
* @param mixed $result
|
596 |
-
*
|
597 |
-
* @return bool Is API result contains an error.
|
598 |
-
*/
|
599 |
-
static function is_api_error_object( $result ) {
|
600 |
-
return (
|
601 |
-
is_object( $result ) &&
|
602 |
-
isset( $result->error ) &&
|
603 |
-
isset( $result->error->message )
|
604 |
-
);
|
605 |
-
}
|
606 |
-
|
607 |
-
/**
|
608 |
-
* Checks if given API result is a non-empty and not an error object.
|
609 |
-
*
|
610 |
-
* @author Vova Feldman (@svovaf)
|
611 |
-
* @since 1.2.1.5
|
612 |
-
*
|
613 |
-
* @param mixed $result
|
614 |
-
* @param string|null $required_property Optional property we want to verify that is set.
|
615 |
-
*
|
616 |
-
* @return bool
|
617 |
-
*/
|
618 |
-
static function is_api_result_object( $result, $required_property = null ) {
|
619 |
-
return (
|
620 |
-
is_object( $result ) &&
|
621 |
-
! isset( $result->error ) &&
|
622 |
-
( empty( $required_property ) || isset( $result->{$required_property} ) )
|
623 |
-
);
|
624 |
-
}
|
625 |
-
|
626 |
-
/**
|
627 |
-
* Checks if given API result is a non-empty entity object with non-empty ID.
|
628 |
-
*
|
629 |
-
* @author Vova Feldman (@svovaf)
|
630 |
-
* @since 1.2.1.5
|
631 |
-
*
|
632 |
-
* @param mixed $result
|
633 |
-
*
|
634 |
-
* @return bool
|
635 |
-
*/
|
636 |
-
static function is_api_result_entity( $result ) {
|
637 |
-
return self::is_api_result_object( $result, 'id' ) &&
|
638 |
-
FS_Entity::is_valid_id( $result->id );
|
639 |
-
}
|
640 |
-
|
641 |
-
/**
|
642 |
-
* Get API result error code. If failed to get code, returns an empty string.
|
643 |
-
*
|
644 |
-
* @author Vova Feldman (@svovaf)
|
645 |
-
* @since 2.0.0
|
646 |
-
*
|
647 |
-
* @param mixed $result
|
648 |
-
*
|
649 |
-
* @return string
|
650 |
-
*/
|
651 |
-
static function get_error_code( $result ) {
|
652 |
-
if ( is_object( $result ) &&
|
653 |
-
isset( $result->error ) &&
|
654 |
-
is_object( $result->error ) &&
|
655 |
-
! empty( $result->error->code )
|
656 |
-
) {
|
657 |
-
return $result->error->code;
|
658 |
-
}
|
659 |
-
|
660 |
-
return '';
|
661 |
-
}
|
662 |
-
|
663 |
-
#endregion
|
664 |
}
|
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 1.0.4
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Class FS_Api
|
15 |
+
*
|
16 |
+
* Wraps Freemius API SDK to handle:
|
17 |
+
* 1. Clock sync.
|
18 |
+
* 2. Fallback to HTTP when HTTPS fails.
|
19 |
+
* 3. Adds caching layer to GET requests.
|
20 |
+
* 4. Adds consistency for failed requests by using last cached version.
|
21 |
+
*/
|
22 |
+
class FS_Api {
|
23 |
+
/**
|
24 |
+
* @var FS_Api[]
|
25 |
+
*/
|
26 |
+
private static $_instances = array();
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var FS_Option_Manager Freemius options, options-manager.
|
30 |
+
*/
|
31 |
+
private static $_options;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* @var FS_Cache_Manager API Caching layer
|
35 |
+
*/
|
36 |
+
private static $_cache;
|
37 |
+
|
38 |
+
/**
|
39 |
+
* @var int Clock diff in seconds between current server to API server.
|
40 |
+
*/
|
41 |
+
private static $_clock_diff;
|
42 |
+
|
43 |
+
/**
|
44 |
+
* @var Freemius_Api_WordPress
|
45 |
+
*/
|
46 |
+
private $_api;
|
47 |
+
|
48 |
+
/**
|
49 |
+
* @var string
|
50 |
+
*/
|
51 |
+
private $_slug;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* @var FS_Logger
|
55 |
+
* @since 1.0.4
|
56 |
+
*/
|
57 |
+
private $_logger;
|
58 |
+
|
59 |
+
/**
|
60 |
+
* @author Leo Fajardo (@leorw)
|
61 |
+
* @since 2.3.0
|
62 |
+
*
|
63 |
+
* @var string
|
64 |
+
*/
|
65 |
+
private $_sdk_version;
|
66 |
+
|
67 |
+
/**
|
68 |
+
* @param string $slug
|
69 |
+
* @param string $scope 'app', 'developer', 'user' or 'install'.
|
70 |
+
* @param number $id Element's id.
|
71 |
+
* @param string $public_key Public key.
|
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 |
+
*/
|
78 |
+
static function instance(
|
79 |
+
$slug,
|
80 |
+
$scope,
|
81 |
+
$id,
|
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 ];
|
96 |
+
}
|
97 |
+
|
98 |
+
private static function _init() {
|
99 |
+
if ( isset( self::$_options ) ) {
|
100 |
+
return;
|
101 |
+
}
|
102 |
+
|
103 |
+
if ( ! class_exists( 'Freemius_Api_WordPress' ) ) {
|
104 |
+
require_once WP_FS__DIR_SDK . '/FreemiusWordPress.php';
|
105 |
+
}
|
106 |
+
|
107 |
+
self::$_options = FS_Option_Manager::get_manager( WP_FS__OPTIONS_OPTION_NAME, true, true );
|
108 |
+
self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
|
109 |
+
|
110 |
+
self::$_clock_diff = self::$_options->get_option( 'api_clock_diff', 0 );
|
111 |
+
Freemius_Api_WordPress::SetClockDiff( self::$_clock_diff );
|
112 |
+
|
113 |
+
if ( self::$_options->get_option( 'api_force_http', false ) ) {
|
114 |
+
Freemius_Api_WordPress::SetHttp();
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* @param string $slug
|
120 |
+
* @param string $scope 'app', 'developer', 'user' or 'install'.
|
121 |
+
* @param number $id Element's id.
|
122 |
+
* @param string $public_key Public key.
|
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,
|
129 |
+
$scope,
|
130 |
+
$id,
|
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 |
+
|
143 |
+
/**
|
144 |
+
* Find clock diff between server and API server, and store the diff locally.
|
145 |
+
*
|
146 |
+
* @param bool|int $diff
|
147 |
+
*
|
148 |
+
* @return bool|int False if clock diff didn't change, otherwise returns the clock diff in seconds.
|
149 |
+
*/
|
150 |
+
private function _sync_clock_diff( $diff = false ) {
|
151 |
+
$this->_logger->entrance();
|
152 |
+
|
153 |
+
// Sync clock and store.
|
154 |
+
$new_clock_diff = ( false === $diff ) ?
|
155 |
+
Freemius_Api_WordPress::FindClockDiff() :
|
156 |
+
$diff;
|
157 |
+
|
158 |
+
if ( $new_clock_diff === self::$_clock_diff ) {
|
159 |
+
return false;
|
160 |
+
}
|
161 |
+
|
162 |
+
self::$_clock_diff = $new_clock_diff;
|
163 |
+
|
164 |
+
// Update API clock's diff.
|
165 |
+
Freemius_Api_WordPress::SetClockDiff( self::$_clock_diff );
|
166 |
+
|
167 |
+
// Store new clock diff in storage.
|
168 |
+
self::$_options->set_option( 'api_clock_diff', self::$_clock_diff, true );
|
169 |
+
|
170 |
+
return $new_clock_diff;
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* Override API call to enable retry with servers' clock auto sync method.
|
175 |
+
*
|
176 |
+
* @param string $path
|
177 |
+
* @param string $method
|
178 |
+
* @param array $params
|
179 |
+
* @param bool $retry Is in retry or first call attempt.
|
180 |
+
*
|
181 |
+
* @return array|mixed|string|void
|
182 |
+
*/
|
183 |
+
private function _call( $path, $method = 'GET', $params = array(), $retry = false ) {
|
184 |
+
$this->_logger->entrance( $method . ':' . $path );
|
185 |
+
|
186 |
+
if ( self::is_temporary_down() ) {
|
187 |
+
$result = $this->get_temporary_unavailable_error();
|
188 |
+
} else {
|
189 |
+
/**
|
190 |
+
* @since 2.3.0 Include the SDK version with all API requests that going through the API manager. IMPORTANT: Only pass the SDK version if the caller didn't include it yet.
|
191 |
+
*/
|
192 |
+
if ( ! empty( $this->_sdk_version ) ) {
|
193 |
+
if ( false === strpos( $path, 'sdk_version=' ) &&
|
194 |
+
! isset( $params['sdk_version'] )
|
195 |
+
) {
|
196 |
+
// Always add the sdk_version param in the querystring. DO NOT INCLUDE IT IN THE BODY PARAMS, OTHERWISE, IT MAY LEAD TO AN UNEXPECTED PARAMS PARSING IN CASES WHERE THE $params IS A REGULAR NON-ASSOCIATIVE ARRAY.
|
197 |
+
$path = add_query_arg( 'sdk_version', $this->_sdk_version, $path );
|
198 |
+
}
|
199 |
+
}
|
200 |
+
|
201 |
+
$result = $this->_api->Api( $path, $method, $params );
|
202 |
+
|
203 |
+
if ( null !== $result &&
|
204 |
+
isset( $result->error ) &&
|
205 |
+
isset( $result->error->code ) &&
|
206 |
+
'request_expired' === $result->error->code
|
207 |
+
) {
|
208 |
+
if ( ! $retry ) {
|
209 |
+
$diff = isset( $result->error->timestamp ) ?
|
210 |
+
( time() - strtotime( $result->error->timestamp ) ) :
|
211 |
+
false;
|
212 |
+
|
213 |
+
// Try to sync clock diff.
|
214 |
+
if ( false !== $this->_sync_clock_diff( $diff ) ) {
|
215 |
+
// Retry call with new synced clock.
|
216 |
+
return $this->_call( $path, $method, $params, true );
|
217 |
+
}
|
218 |
+
}
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
if ( $this->_logger->is_on() && self::is_api_error( $result ) ) {
|
223 |
+
// Log API errors.
|
224 |
+
$this->_logger->api_error( $result );
|
225 |
+
}
|
226 |
+
|
227 |
+
return $result;
|
228 |
+
}
|
229 |
+
|
230 |
+
/**
|
231 |
+
* Override API call to wrap it in servers' clock sync method.
|
232 |
+
*
|
233 |
+
* @param string $path
|
234 |
+
* @param string $method
|
235 |
+
* @param array $params
|
236 |
+
*
|
237 |
+
* @return array|mixed|string|void
|
238 |
+
* @throws Freemius_Exception
|
239 |
+
*/
|
240 |
+
function call( $path, $method = 'GET', $params = array() ) {
|
241 |
+
return $this->_call( $path, $method, $params );
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Get API request URL signed via query string.
|
246 |
+
*
|
247 |
+
* @param string $path
|
248 |
+
*
|
249 |
+
* @return string
|
250 |
+
*/
|
251 |
+
function get_signed_url( $path ) {
|
252 |
+
return $this->_api->GetSignedUrl( $path );
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* @param string $path
|
257 |
+
* @param bool $flush
|
258 |
+
* @param int $expiration (optional) Time until expiration in seconds from now, defaults to 24 hours
|
259 |
+
*
|
260 |
+
* @return stdClass|mixed
|
261 |
+
*/
|
262 |
+
function get( $path = '/', $flush = false, $expiration = WP_FS__TIME_24_HOURS_IN_SEC ) {
|
263 |
+
$this->_logger->entrance( $path );
|
264 |
+
|
265 |
+
$cache_key = $this->get_cache_key( $path );
|
266 |
+
|
267 |
+
// Always flush during development.
|
268 |
+
if ( WP_FS__DEV_MODE || $this->_api->IsSandbox() ) {
|
269 |
+
$flush = true;
|
270 |
+
}
|
271 |
+
|
272 |
+
$cached_result = self::$_cache->get( $cache_key );
|
273 |
+
|
274 |
+
if ( $flush || ! self::$_cache->has_valid( $cache_key, $expiration ) ) {
|
275 |
+
$result = $this->call( $path );
|
276 |
+
|
277 |
+
if ( ! is_object( $result ) || isset( $result->error ) ) {
|
278 |
+
// Api returned an error.
|
279 |
+
if ( is_object( $cached_result ) &&
|
280 |
+
! isset( $cached_result->error )
|
281 |
+
) {
|
282 |
+
// If there was an error during a newer data fetch,
|
283 |
+
// fallback to older data version.
|
284 |
+
$result = $cached_result;
|
285 |
+
|
286 |
+
if ( $this->_logger->is_on() ) {
|
287 |
+
$this->_logger->warn( 'Fallback to cached API result: ' . var_export( $cached_result, true ) );
|
288 |
+
}
|
289 |
+
} else {
|
290 |
+
if ( is_object( $result ) && isset( $result->error->http ) && 404 == $result->error->http ) {
|
291 |
+
/**
|
292 |
+
* If the response code is 404, cache the result for half of the `$expiration`.
|
293 |
+
*
|
294 |
+
* @author Leo Fajardo (@leorw)
|
295 |
+
* @since 2.2.4
|
296 |
+
*/
|
297 |
+
$expiration /= 2;
|
298 |
+
} else {
|
299 |
+
// If no older data version and the response code is not 404, return result without
|
300 |
+
// caching the error.
|
301 |
+
return $result;
|
302 |
+
}
|
303 |
+
}
|
304 |
+
}
|
305 |
+
|
306 |
+
self::$_cache->set( $cache_key, $result, $expiration );
|
307 |
+
|
308 |
+
$cached_result = $result;
|
309 |
+
} else {
|
310 |
+
$this->_logger->log( 'Using cached API result.' );
|
311 |
+
}
|
312 |
+
|
313 |
+
return $cached_result;
|
314 |
+
}
|
315 |
+
|
316 |
+
/**
|
317 |
+
* Check if there's a cached version of the API request.
|
318 |
+
*
|
319 |
+
* @author Vova Feldman (@svovaf)
|
320 |
+
* @since 1.2.1
|
321 |
+
*
|
322 |
+
* @param string $path
|
323 |
+
* @param string $method
|
324 |
+
* @param array $params
|
325 |
+
*
|
326 |
+
* @return bool
|
327 |
+
*/
|
328 |
+
function is_cached( $path, $method = 'GET', $params = array() ) {
|
329 |
+
$cache_key = $this->get_cache_key( $path, $method, $params );
|
330 |
+
|
331 |
+
return self::$_cache->has_valid( $cache_key );
|
332 |
+
}
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Invalidate a cached version of the API request.
|
336 |
+
*
|
337 |
+
* @author Vova Feldman (@svovaf)
|
338 |
+
* @since 1.2.1.5
|
339 |
+
*
|
340 |
+
* @param string $path
|
341 |
+
* @param string $method
|
342 |
+
* @param array $params
|
343 |
+
*/
|
344 |
+
function purge_cache( $path, $method = 'GET', $params = array() ) {
|
345 |
+
$this->_logger->entrance( "{$method}:{$path}" );
|
346 |
+
|
347 |
+
$cache_key = $this->get_cache_key( $path, $method, $params );
|
348 |
+
|
349 |
+
self::$_cache->purge( $cache_key );
|
350 |
+
}
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Invalidate a cached version of the API request.
|
354 |
+
*
|
355 |
+
* @author Vova Feldman (@svovaf)
|
356 |
+
* @since 2.0.0
|
357 |
+
*
|
358 |
+
* @param string $path
|
359 |
+
* @param int $expiration
|
360 |
+
* @param string $method
|
361 |
+
* @param array $params
|
362 |
+
*/
|
363 |
+
function update_cache_expiration( $path, $expiration = WP_FS__TIME_24_HOURS_IN_SEC, $method = 'GET', $params = array() ) {
|
364 |
+
$this->_logger->entrance( "{$method}:{$path}:{$expiration}" );
|
365 |
+
|
366 |
+
$cache_key = $this->get_cache_key( $path, $method, $params );
|
367 |
+
|
368 |
+
self::$_cache->update_expiration( $cache_key, $expiration );
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* @param string $path
|
373 |
+
* @param string $method
|
374 |
+
* @param array $params
|
375 |
+
*
|
376 |
+
* @return string
|
377 |
+
* @throws \Freemius_Exception
|
378 |
+
*/
|
379 |
+
private function get_cache_key( $path, $method = 'GET', $params = array() ) {
|
380 |
+
$canonized = $this->_api->CanonizePath( $path );
|
381 |
+
// $exploded = explode('/', $canonized);
|
382 |
+
// return $method . '_' . array_pop($exploded) . '_' . md5($canonized . json_encode($params));
|
383 |
+
return strtolower( $method . ':' . $canonized ) . ( ! empty( $params ) ? '#' . md5( json_encode( $params ) ) : '' );
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Test API connectivity.
|
388 |
+
*
|
389 |
+
* @author Vova Feldman (@svovaf)
|
390 |
+
* @since 1.0.9 If fails, try to fallback to HTTP.
|
391 |
+
* @since 1.1.6 Added a 5-min caching mechanism, to prevent from overloading the server if the API if
|
392 |
+
* temporary down.
|
393 |
+
*
|
394 |
+
* @return bool True if successful connectivity to the API.
|
395 |
+
*/
|
396 |
+
static function test() {
|
397 |
+
self::_init();
|
398 |
+
|
399 |
+
$cache_key = 'ping_test';
|
400 |
+
|
401 |
+
$test = self::$_cache->get_valid( $cache_key, null );
|
402 |
+
|
403 |
+
if ( is_null( $test ) ) {
|
404 |
+
$test = Freemius_Api_WordPress::Test();
|
405 |
+
|
406 |
+
if ( false === $test && Freemius_Api_WordPress::IsHttps() ) {
|
407 |
+
// Fallback to HTTP, since HTTPS fails.
|
408 |
+
Freemius_Api_WordPress::SetHttp();
|
409 |
+
|
410 |
+
self::$_options->set_option( 'api_force_http', true, true );
|
411 |
+
|
412 |
+
$test = Freemius_Api_WordPress::Test();
|
413 |
+
|
414 |
+
if ( false === $test ) {
|
415 |
+
/**
|
416 |
+
* API connectivity test fail also in HTTP request, therefore,
|
417 |
+
* fallback to HTTPS to keep connection secure.
|
418 |
+
*
|
419 |
+
* @since 1.1.6
|
420 |
+
*/
|
421 |
+
self::$_options->set_option( 'api_force_http', false, true );
|
422 |
+
}
|
423 |
+
}
|
424 |
+
|
425 |
+
self::$_cache->set( $cache_key, $test, WP_FS__TIME_5_MIN_IN_SEC );
|
426 |
+
}
|
427 |
+
|
428 |
+
return $test;
|
429 |
+
}
|
430 |
+
|
431 |
+
/**
|
432 |
+
* Check if API is temporary down.
|
433 |
+
*
|
434 |
+
* @author Vova Feldman (@svovaf)
|
435 |
+
* @since 1.1.6
|
436 |
+
*
|
437 |
+
* @return bool
|
438 |
+
*/
|
439 |
+
static function is_temporary_down() {
|
440 |
+
self::_init();
|
441 |
+
|
442 |
+
$test = self::$_cache->get_valid( 'ping_test', null );
|
443 |
+
|
444 |
+
return ( false === $test );
|
445 |
+
}
|
446 |
+
|
447 |
+
/**
|
448 |
+
* @author Vova Feldman (@svovaf)
|
449 |
+
* @since 1.1.6
|
450 |
+
*
|
451 |
+
* @return object
|
452 |
+
*/
|
453 |
+
private function get_temporary_unavailable_error() {
|
454 |
+
return (object) array(
|
455 |
+
'error' => (object) array(
|
456 |
+
'type' => 'TemporaryUnavailable',
|
457 |
+
'message' => 'API is temporary unavailable, please retry in ' . ( self::$_cache->get_record_expiration( 'ping_test' ) - WP_FS__SCRIPT_START_TIME ) . ' sec.',
|
458 |
+
'code' => 'temporary_unavailable',
|
459 |
+
'http' => 503
|
460 |
+
)
|
461 |
+
);
|
462 |
+
}
|
463 |
+
|
464 |
+
/**
|
465 |
+
* Ping API for connectivity test, and return result object.
|
466 |
+
*
|
467 |
+
* @author Vova Feldman (@svovaf)
|
468 |
+
* @since 1.0.9
|
469 |
+
*
|
470 |
+
* @param null|string $unique_anonymous_id
|
471 |
+
* @param array $params
|
472 |
+
*
|
473 |
+
* @return object
|
474 |
+
*/
|
475 |
+
function ping( $unique_anonymous_id = null, $params = array() ) {
|
476 |
+
$this->_logger->entrance();
|
477 |
+
|
478 |
+
if ( self::is_temporary_down() ) {
|
479 |
+
return $this->get_temporary_unavailable_error();
|
480 |
+
}
|
481 |
+
|
482 |
+
$pong = is_null( $unique_anonymous_id ) ?
|
483 |
+
Freemius_Api_WordPress::Ping() :
|
484 |
+
$this->_call( 'ping.json?' . http_build_query( array_merge(
|
485 |
+
array( 'uid' => $unique_anonymous_id ),
|
486 |
+
$params
|
487 |
+
) ) );
|
488 |
+
|
489 |
+
if ( $this->is_valid_ping( $pong ) ) {
|
490 |
+
return $pong;
|
491 |
+
}
|
492 |
+
|
493 |
+
if ( self::should_try_with_http( $pong ) ) {
|
494 |
+
// Fallback to HTTP, since HTTPS fails.
|
495 |
+
Freemius_Api_WordPress::SetHttp();
|
496 |
+
|
497 |
+
self::$_options->set_option( 'api_force_http', true, true );
|
498 |
+
|
499 |
+
$pong = is_null( $unique_anonymous_id ) ?
|
500 |
+
Freemius_Api_WordPress::Ping() :
|
501 |
+
$this->_call( 'ping.json?' . http_build_query( array_merge(
|
502 |
+
array( 'uid' => $unique_anonymous_id ),
|
503 |
+
$params
|
504 |
+
) ) );
|
505 |
+
|
506 |
+
if ( ! $this->is_valid_ping( $pong ) ) {
|
507 |
+
self::$_options->set_option( 'api_force_http', false, true );
|
508 |
+
}
|
509 |
+
}
|
510 |
+
|
511 |
+
return $pong;
|
512 |
+
}
|
513 |
+
|
514 |
+
/**
|
515 |
+
* Check if based on the API result we should try
|
516 |
+
* to re-run the same request with HTTP instead of HTTPS.
|
517 |
+
*
|
518 |
+
* @author Vova Feldman (@svovaf)
|
519 |
+
* @since 1.1.6
|
520 |
+
*
|
521 |
+
* @param $result
|
522 |
+
*
|
523 |
+
* @return bool
|
524 |
+
*/
|
525 |
+
private static function should_try_with_http( $result ) {
|
526 |
+
if ( ! Freemius_Api_WordPress::IsHttps() ) {
|
527 |
+
return false;
|
528 |
+
}
|
529 |
+
|
530 |
+
return ( ! is_object( $result ) ||
|
531 |
+
! isset( $result->error ) ||
|
532 |
+
! isset( $result->error->code ) ||
|
533 |
+
! in_array( $result->error->code, array(
|
534 |
+
'curl_missing',
|
535 |
+
'cloudflare_ddos_protection',
|
536 |
+
'maintenance_mode',
|
537 |
+
'squid_cache_block',
|
538 |
+
'too_many_requests',
|
539 |
+
) ) );
|
540 |
+
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* Check if valid ping request result.
|
545 |
+
*
|
546 |
+
* @author Vova Feldman (@svovaf)
|
547 |
+
* @since 1.1.1
|
548 |
+
*
|
549 |
+
* @param mixed $pong
|
550 |
+
*
|
551 |
+
* @return bool
|
552 |
+
*/
|
553 |
+
function is_valid_ping( $pong ) {
|
554 |
+
return Freemius_Api_WordPress::Test( $pong );
|
555 |
+
}
|
556 |
+
|
557 |
+
function get_url( $path = '' ) {
|
558 |
+
return Freemius_Api_WordPress::GetUrl( $path, $this->_api->IsSandbox() );
|
559 |
+
}
|
560 |
+
|
561 |
+
/**
|
562 |
+
* Clear API cache.
|
563 |
+
*
|
564 |
+
* @author Vova Feldman (@svovaf)
|
565 |
+
* @since 1.0.9
|
566 |
+
*/
|
567 |
+
static function clear_cache() {
|
568 |
+
self::_init();
|
569 |
+
|
570 |
+
self::$_cache = FS_Cache_Manager::get_manager( WP_FS__API_CACHE_OPTION_NAME );
|
571 |
+
self::$_cache->clear();
|
572 |
+
}
|
573 |
+
|
574 |
+
#----------------------------------------------------------------------------------
|
575 |
+
#region Error Handling
|
576 |
+
#----------------------------------------------------------------------------------
|
577 |
+
|
578 |
+
/**
|
579 |
+
* @author Vova Feldman (@svovaf)
|
580 |
+
* @since 1.2.1.5
|
581 |
+
*
|
582 |
+
* @param mixed $result
|
583 |
+
*
|
584 |
+
* @return bool Is API result contains an error.
|
585 |
+
*/
|
586 |
+
static function is_api_error( $result ) {
|
587 |
+
return ( is_object( $result ) && isset( $result->error ) ) ||
|
588 |
+
is_string( $result );
|
589 |
+
}
|
590 |
+
|
591 |
+
/**
|
592 |
+
* @author Vova Feldman (@svovaf)
|
593 |
+
* @since 2.0.0
|
594 |
+
*
|
595 |
+
* @param mixed $result
|
596 |
+
*
|
597 |
+
* @return bool Is API result contains an error.
|
598 |
+
*/
|
599 |
+
static function is_api_error_object( $result ) {
|
600 |
+
return (
|
601 |
+
is_object( $result ) &&
|
602 |
+
isset( $result->error ) &&
|
603 |
+
isset( $result->error->message )
|
604 |
+
);
|
605 |
+
}
|
606 |
+
|
607 |
+
/**
|
608 |
+
* Checks if given API result is a non-empty and not an error object.
|
609 |
+
*
|
610 |
+
* @author Vova Feldman (@svovaf)
|
611 |
+
* @since 1.2.1.5
|
612 |
+
*
|
613 |
+
* @param mixed $result
|
614 |
+
* @param string|null $required_property Optional property we want to verify that is set.
|
615 |
+
*
|
616 |
+
* @return bool
|
617 |
+
*/
|
618 |
+
static function is_api_result_object( $result, $required_property = null ) {
|
619 |
+
return (
|
620 |
+
is_object( $result ) &&
|
621 |
+
! isset( $result->error ) &&
|
622 |
+
( empty( $required_property ) || isset( $result->{$required_property} ) )
|
623 |
+
);
|
624 |
+
}
|
625 |
+
|
626 |
+
/**
|
627 |
+
* Checks if given API result is a non-empty entity object with non-empty ID.
|
628 |
+
*
|
629 |
+
* @author Vova Feldman (@svovaf)
|
630 |
+
* @since 1.2.1.5
|
631 |
+
*
|
632 |
+
* @param mixed $result
|
633 |
+
*
|
634 |
+
* @return bool
|
635 |
+
*/
|
636 |
+
static function is_api_result_entity( $result ) {
|
637 |
+
return self::is_api_result_object( $result, 'id' ) &&
|
638 |
+
FS_Entity::is_valid_id( $result->id );
|
639 |
+
}
|
640 |
+
|
641 |
+
/**
|
642 |
+
* Get API result error code. If failed to get code, returns an empty string.
|
643 |
+
*
|
644 |
+
* @author Vova Feldman (@svovaf)
|
645 |
+
* @since 2.0.0
|
646 |
+
*
|
647 |
+
* @param mixed $result
|
648 |
+
*
|
649 |
+
* @return string
|
650 |
+
*/
|
651 |
+
static function get_error_code( $result ) {
|
652 |
+
if ( is_object( $result ) &&
|
653 |
+
isset( $result->error ) &&
|
654 |
+
is_object( $result->error ) &&
|
655 |
+
! empty( $result->error->code )
|
656 |
+
) {
|
657 |
+
return $result->error->code;
|
658 |
+
}
|
659 |
+
|
660 |
+
return '';
|
661 |
+
}
|
662 |
+
|
663 |
+
#endregion
|
664 |
}
|
freemius/includes/class-fs-options.php
CHANGED
@@ -1,431 +1,431 @@
|
|
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 1.2.3
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Class FS_Options
|
15 |
-
*
|
16 |
-
* A wrapper class for handling network level and single site level options.
|
17 |
-
*/
|
18 |
-
class FS_Options {
|
19 |
-
/**
|
20 |
-
* @var string
|
21 |
-
*/
|
22 |
-
private $_id;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* @var array[string]FS_Options {
|
26 |
-
* @key string
|
27 |
-
* @value FS_Options
|
28 |
-
* }
|
29 |
-
*/
|
30 |
-
private static $_instances;
|
31 |
-
|
32 |
-
/**
|
33 |
-
* @var FS_Option_Manager Site level options.
|
34 |
-
*/
|
35 |
-
private $_options;
|
36 |
-
|
37 |
-
/**
|
38 |
-
* @var FS_Option_Manager Network level options.
|
39 |
-
*/
|
40 |
-
private $_network_options;
|
41 |
-
|
42 |
-
/**
|
43 |
-
* @var int The ID of the blog that is associated with the current site level options.
|
44 |
-
*/
|
45 |
-
private $_blog_id = 0;
|
46 |
-
|
47 |
-
/**
|
48 |
-
* @var bool
|
49 |
-
*/
|
50 |
-
private $_is_multisite;
|
51 |
-
|
52 |
-
/**
|
53 |
-
* @var string[] Lazy collection of params on the site level.
|
54 |
-
*/
|
55 |
-
private static $_SITE_OPTIONS_MAP;
|
56 |
-
|
57 |
-
/**
|
58 |
-
* @author Leo Fajardo (@leorw)
|
59 |
-
* @since 2.0.0
|
60 |
-
*
|
61 |
-
* @param string $id
|
62 |
-
* @param bool $load
|
63 |
-
*
|
64 |
-
* @return FS_Options
|
65 |
-
*/
|
66 |
-
static function instance( $id, $load = false ) {
|
67 |
-
if ( ! isset( self::$_instances[ $id ] ) ) {
|
68 |
-
self::$_instances[ $id ] = new FS_Options( $id, $load );
|
69 |
-
}
|
70 |
-
|
71 |
-
return self::$_instances[ $id ];
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* @author Leo Fajardo (@leorw)
|
76 |
-
* @since 2.0.0
|
77 |
-
*
|
78 |
-
* @param string $id
|
79 |
-
* @param bool $load
|
80 |
-
*/
|
81 |
-
private function __construct( $id, $load = false ) {
|
82 |
-
$this->_id = $id;
|
83 |
-
$this->_is_multisite = is_multisite();
|
84 |
-
|
85 |
-
if ( $this->_is_multisite ) {
|
86 |
-
$this->_blog_id = get_current_blog_id();
|
87 |
-
$this->_network_options = FS_Option_Manager::get_manager( $id, $load, true );
|
88 |
-
}
|
89 |
-
|
90 |
-
$this->_options = FS_Option_Manager::get_manager( $id, $load, $this->_blog_id );
|
91 |
-
}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Switch the context of the site level options manager.
|
95 |
-
*
|
96 |
-
* @author Vova Feldman (@svovaf)
|
97 |
-
* @since 2.0.0
|
98 |
-
*
|
99 |
-
* @param $blog_id
|
100 |
-
*/
|
101 |
-
function set_site_blog_context( $blog_id ) {
|
102 |
-
$this->_blog_id = $blog_id;
|
103 |
-
|
104 |
-
$this->_options = FS_Option_Manager::get_manager( $this->_id, false, $this->_blog_id );
|
105 |
-
}
|
106 |
-
|
107 |
-
/**
|
108 |
-
* @author Leo Fajardo (@leorw)
|
109 |
-
*
|
110 |
-
* @param string $option
|
111 |
-
* @param mixed $default
|
112 |
-
* @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::$_SITE_LEVEL_PARAMS).
|
113 |
-
*
|
114 |
-
* @return mixed
|
115 |
-
*/
|
116 |
-
function get_option( $option, $default = null, $network_level_or_blog_id = null ) {
|
117 |
-
if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
|
118 |
-
return $this->_network_options->get_option( $option, $default );
|
119 |
-
}
|
120 |
-
|
121 |
-
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
122 |
-
|
123 |
-
return $site_options->get_option( $option, $default );
|
124 |
-
}
|
125 |
-
|
126 |
-
/**
|
127 |
-
* @author Leo Fajardo (@leorw)
|
128 |
-
* @since 2.0.0
|
129 |
-
*
|
130 |
-
* @param string $option
|
131 |
-
* @param mixed $value
|
132 |
-
* @param bool $flush
|
133 |
-
* @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::$_SITE_LEVEL_PARAMS).
|
134 |
-
*/
|
135 |
-
function set_option( $option, $value, $flush = false, $network_level_or_blog_id = null ) {
|
136 |
-
if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
|
137 |
-
$this->_network_options->set_option( $option, $value, $flush );
|
138 |
-
} else {
|
139 |
-
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
140 |
-
$site_options->set_option( $option, $value, $flush );
|
141 |
-
}
|
142 |
-
}
|
143 |
-
|
144 |
-
/**
|
145 |
-
* @author Vova Feldman (@svovaf)
|
146 |
-
* @since 2.0.0
|
147 |
-
*
|
148 |
-
* @param string $option
|
149 |
-
* @param bool $flush
|
150 |
-
* @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::$_SITE_LEVEL_PARAMS).
|
151 |
-
*/
|
152 |
-
function unset_option( $option, $flush = false, $network_level_or_blog_id = null ) {
|
153 |
-
if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
|
154 |
-
$this->_network_options->unset_option( $option, $flush );
|
155 |
-
} else {
|
156 |
-
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
157 |
-
$site_options->unset_option( $option, $flush );
|
158 |
-
}
|
159 |
-
}
|
160 |
-
|
161 |
-
/**
|
162 |
-
* @author Leo Fajardo (@leorw)
|
163 |
-
* @since 2.0.0
|
164 |
-
*
|
165 |
-
* @param bool $flush
|
166 |
-
* @param bool $network_level
|
167 |
-
*/
|
168 |
-
function load( $flush = false, $network_level = true ) {
|
169 |
-
if ( $this->_is_multisite && $network_level ) {
|
170 |
-
$this->_network_options->load( $flush );
|
171 |
-
} else {
|
172 |
-
$this->_options->load( $flush );
|
173 |
-
}
|
174 |
-
}
|
175 |
-
|
176 |
-
/**
|
177 |
-
* @author Leo Fajardo (@leorw)
|
178 |
-
* @since 2.0.0
|
179 |
-
*
|
180 |
-
* @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`, store both network storage and the current context blog storage.
|
181 |
-
*/
|
182 |
-
function store( $network_level_or_blog_id = null ) {
|
183 |
-
if ( ! $this->_is_multisite ||
|
184 |
-
false === $network_level_or_blog_id ||
|
185 |
-
0 == $network_level_or_blog_id ||
|
186 |
-
is_null( $network_level_or_blog_id )
|
187 |
-
) {
|
188 |
-
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
189 |
-
$site_options->store();
|
190 |
-
}
|
191 |
-
|
192 |
-
if ( $this->_is_multisite &&
|
193 |
-
( is_null( $network_level_or_blog_id ) || true === $network_level_or_blog_id )
|
194 |
-
) {
|
195 |
-
$this->_network_options->store();
|
196 |
-
}
|
197 |
-
}
|
198 |
-
|
199 |
-
/**
|
200 |
-
* @author Vova Feldman (@svovaf)
|
201 |
-
* @since 2.0.0
|
202 |
-
*
|
203 |
-
* @param int|null|bool $network_level_or_blog_id
|
204 |
-
* @param bool $flush
|
205 |
-
*/
|
206 |
-
function clear( $network_level_or_blog_id = null, $flush = false ) {
|
207 |
-
if ( ! $this->_is_multisite ||
|
208 |
-
false === $network_level_or_blog_id ||
|
209 |
-
is_null( $network_level_or_blog_id ) ||
|
210 |
-
is_numeric( $network_level_or_blog_id )
|
211 |
-
) {
|
212 |
-
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
213 |
-
$site_options->clear( $flush );
|
214 |
-
}
|
215 |
-
|
216 |
-
if ( $this->_is_multisite &&
|
217 |
-
( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
|
218 |
-
) {
|
219 |
-
$this->_network_options->clear( $flush );
|
220 |
-
}
|
221 |
-
}
|
222 |
-
|
223 |
-
/**
|
224 |
-
* Migration script to the new storage data structure that is network compatible.
|
225 |
-
*
|
226 |
-
* IMPORTANT:
|
227 |
-
* This method should be executed only after it is determined if this is a network
|
228 |
-
* level compatible product activation.
|
229 |
-
*
|
230 |
-
* @author Vova Feldman (@svovaf)
|
231 |
-
* @since 2.0.0
|
232 |
-
*
|
233 |
-
* @param int $blog_id
|
234 |
-
*/
|
235 |
-
function migrate_to_network( $blog_id = 0 ) {
|
236 |
-
if ( ! $this->_is_multisite ) {
|
237 |
-
return;
|
238 |
-
}
|
239 |
-
|
240 |
-
$updated = false;
|
241 |
-
|
242 |
-
$site_options = $this->get_site_options( $blog_id );
|
243 |
-
|
244 |
-
$keys = $site_options->get_options_keys();
|
245 |
-
|
246 |
-
foreach ( $keys as $option ) {
|
247 |
-
if ( $this->is_site_option( $option ) ||
|
248 |
-
// Don't move admin notices to the network storage.
|
249 |
-
in_array($option, array(
|
250 |
-
// Don't move admin notices to the network storage.
|
251 |
-
'admin_notices',
|
252 |
-
// Don't migrate the module specific data, it will be migrated by the FS_Storage.
|
253 |
-
'plugin_data',
|
254 |
-
'theme_data',
|
255 |
-
))
|
256 |
-
) {
|
257 |
-
continue;
|
258 |
-
}
|
259 |
-
|
260 |
-
$option_updated = false;
|
261 |
-
|
262 |
-
// Migrate option to the network storage.
|
263 |
-
$site_option = $site_options->get_option( $option );
|
264 |
-
|
265 |
-
if ( ! $this->_network_options->has_option( $option ) ) {
|
266 |
-
// Option not set on the network level, so just set it.
|
267 |
-
$this->_network_options->set_option( $option, $site_option, false );
|
268 |
-
|
269 |
-
$option_updated = true;
|
270 |
-
} else {
|
271 |
-
// Option already set on the network level, so we need to merge it inelegantly.
|
272 |
-
$network_option = $this->_network_options->get_option( $option );
|
273 |
-
|
274 |
-
if ( is_array( $network_option ) && is_array( $site_option ) ) {
|
275 |
-
// Option is an array.
|
276 |
-
foreach ( $site_option as $key => $value ) {
|
277 |
-
if ( ! isset( $network_option[ $key ] ) ) {
|
278 |
-
$network_option[ $key ] = $value;
|
279 |
-
|
280 |
-
$option_updated = true;
|
281 |
-
} else if ( is_array( $network_option[ $key ] ) && is_array( $value ) ) {
|
282 |
-
if ( empty( $network_option[ $key ] ) ) {
|
283 |
-
$network_option[ $key ] = $value;
|
284 |
-
|
285 |
-
$option_updated = true;
|
286 |
-
} else if ( empty( $value ) ) {
|
287 |
-
// Do nothing.
|
288 |
-
} else {
|
289 |
-
reset($value);
|
290 |
-
$first_key = key($value);
|
291 |
-
if ( $value[$first_key] instanceof FS_Entity ) {
|
292 |
-
// Merge entities by IDs.
|
293 |
-
$network_entities_ids = array();
|
294 |
-
foreach ( $network_option[ $key ] as $entity ) {
|
295 |
-
$network_entities_ids[ $entity->id ] = true;
|
296 |
-
}
|
297 |
-
|
298 |
-
foreach ( $value as $entity ) {
|
299 |
-
if ( ! isset( $network_entities_ids[ $entity->id ] ) ) {
|
300 |
-
$network_option[ $key ][] = $entity;
|
301 |
-
|
302 |
-
$option_updated = true;
|
303 |
-
}
|
304 |
-
}
|
305 |
-
}
|
306 |
-
}
|
307 |
-
}
|
308 |
-
}
|
309 |
-
}
|
310 |
-
|
311 |
-
if ( $option_updated ) {
|
312 |
-
$this->_network_options->set_option( $option, $network_option, false );
|
313 |
-
}
|
314 |
-
}
|
315 |
-
|
316 |
-
/**
|
317 |
-
* Remove the option from site level storage.
|
318 |
-
*
|
319 |
-
* IMPORTANT:
|
320 |
-
* The line below is intentionally commented since we want to preserve the option
|
321 |
-
* on the site storage level for "downgrade compatibility". Basically, if the user
|
322 |
-
* will downgrade to an older version of the plugin with the prev storage structure,
|
323 |
-
* it will continue working.
|
324 |
-
*
|
325 |
-
* @todo After a few releases we can remove this.
|
326 |
-
*/
|
327 |
-
// $site_options->unset_option($option, false);
|
328 |
-
|
329 |
-
if ( $option_updated ) {
|
330 |
-
$updated = true;
|
331 |
-
}
|
332 |
-
}
|
333 |
-
|
334 |
-
if ( ! $updated ) {
|
335 |
-
return;
|
336 |
-
}
|
337 |
-
|
338 |
-
// Update network level storage.
|
339 |
-
$this->_network_options->store();
|
340 |
-
// $site_options->store();
|
341 |
-
}
|
342 |
-
|
343 |
-
|
344 |
-
#--------------------------------------------------------------------------------
|
345 |
-
#region Helper Methods
|
346 |
-
#--------------------------------------------------------------------------------
|
347 |
-
|
348 |
-
/**
|
349 |
-
* We don't want to load the map right away since it's not even needed in a non-MS environment.
|
350 |
-
*
|
351 |
-
* @author Vova Feldman (@svovaf)
|
352 |
-
* @since 2.0.0
|
353 |
-
*/
|
354 |
-
private static function load_site_options_map() {
|
355 |
-
self::$_SITE_OPTIONS_MAP = array(
|
356 |
-
'sites' => true,
|
357 |
-
'theme_sites' => true,
|
358 |
-
'unique_id' => true,
|
359 |
-
'active_plugins' => true,
|
360 |
-
);
|
361 |
-
}
|
362 |
-
|
363 |
-
/**
|
364 |
-
* @author Vova Feldman (@svovaf)
|
365 |
-
* @since 2.0.0
|
366 |
-
*
|
367 |
-
* @param string $option
|
368 |
-
*
|
369 |
-
* @return bool
|
370 |
-
*/
|
371 |
-
private function is_site_option( $option ) {
|
372 |
-
if ( WP_FS__ACCOUNTS_OPTION_NAME != $this->_id ) {
|
373 |
-
return false;
|
374 |
-
}
|
375 |
-
|
376 |
-
if ( ! isset( self::$_SITE_OPTIONS_MAP ) ) {
|
377 |
-
self::load_site_options_map();
|
378 |
-
}
|
379 |
-
|
380 |
-
return isset( self::$_SITE_OPTIONS_MAP[ $option ] );
|
381 |
-
}
|
382 |
-
|
383 |
-
/**
|
384 |
-
* @author Vova Feldman (@svovaf)
|
385 |
-
* @since 2.0.0
|
386 |
-
*
|
387 |
-
* @param int $blog_id
|
388 |
-
*
|
389 |
-
* @return FS_Option_Manager
|
390 |
-
*/
|
391 |
-
private function get_site_options( $blog_id = 0 ) {
|
392 |
-
if ( 0 == $blog_id || $blog_id == $this->_blog_id ) {
|
393 |
-
return $this->_options;
|
394 |
-
}
|
395 |
-
|
396 |
-
return FS_Option_Manager::get_manager( $this->_id, true, $blog_id );
|
397 |
-
}
|
398 |
-
|
399 |
-
/**
|
400 |
-
* Check if an option should be stored on the MS network storage.
|
401 |
-
*
|
402 |
-
* @author Vova Feldman (@svovaf)
|
403 |
-
* @since 2.0.0
|
404 |
-
*
|
405 |
-
* @param string $option
|
406 |
-
* @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::$_SITE_LEVEL_PARAMS).
|
407 |
-
*
|
408 |
-
* @return bool
|
409 |
-
*/
|
410 |
-
private function should_use_network_storage( $option, $network_level_or_blog_id = null ) {
|
411 |
-
if ( ! $this->_is_multisite ) {
|
412 |
-
// Not a multisite environment.
|
413 |
-
return false;
|
414 |
-
}
|
415 |
-
|
416 |
-
if ( is_numeric( $network_level_or_blog_id ) ) {
|
417 |
-
// Explicitly asked to use a specified blog storage.
|
418 |
-
return false;
|
419 |
-
}
|
420 |
-
|
421 |
-
if ( is_bool( $network_level_or_blog_id ) ) {
|
422 |
-
// Explicitly specified whether should use the network or blog level storage.
|
423 |
-
return $network_level_or_blog_id;
|
424 |
-
}
|
425 |
-
|
426 |
-
// Determine which storage to use based on the option.
|
427 |
-
return ! $this->is_site_option( $option );
|
428 |
-
}
|
429 |
-
|
430 |
-
#endregion
|
431 |
}
|
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 1.2.3
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Class FS_Options
|
15 |
+
*
|
16 |
+
* A wrapper class for handling network level and single site level options.
|
17 |
+
*/
|
18 |
+
class FS_Options {
|
19 |
+
/**
|
20 |
+
* @var string
|
21 |
+
*/
|
22 |
+
private $_id;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @var array[string]FS_Options {
|
26 |
+
* @key string
|
27 |
+
* @value FS_Options
|
28 |
+
* }
|
29 |
+
*/
|
30 |
+
private static $_instances;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @var FS_Option_Manager Site level options.
|
34 |
+
*/
|
35 |
+
private $_options;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @var FS_Option_Manager Network level options.
|
39 |
+
*/
|
40 |
+
private $_network_options;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* @var int The ID of the blog that is associated with the current site level options.
|
44 |
+
*/
|
45 |
+
private $_blog_id = 0;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @var bool
|
49 |
+
*/
|
50 |
+
private $_is_multisite;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @var string[] Lazy collection of params on the site level.
|
54 |
+
*/
|
55 |
+
private static $_SITE_OPTIONS_MAP;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* @author Leo Fajardo (@leorw)
|
59 |
+
* @since 2.0.0
|
60 |
+
*
|
61 |
+
* @param string $id
|
62 |
+
* @param bool $load
|
63 |
+
*
|
64 |
+
* @return FS_Options
|
65 |
+
*/
|
66 |
+
static function instance( $id, $load = false ) {
|
67 |
+
if ( ! isset( self::$_instances[ $id ] ) ) {
|
68 |
+
self::$_instances[ $id ] = new FS_Options( $id, $load );
|
69 |
+
}
|
70 |
+
|
71 |
+
return self::$_instances[ $id ];
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @author Leo Fajardo (@leorw)
|
76 |
+
* @since 2.0.0
|
77 |
+
*
|
78 |
+
* @param string $id
|
79 |
+
* @param bool $load
|
80 |
+
*/
|
81 |
+
private function __construct( $id, $load = false ) {
|
82 |
+
$this->_id = $id;
|
83 |
+
$this->_is_multisite = is_multisite();
|
84 |
+
|
85 |
+
if ( $this->_is_multisite ) {
|
86 |
+
$this->_blog_id = get_current_blog_id();
|
87 |
+
$this->_network_options = FS_Option_Manager::get_manager( $id, $load, true );
|
88 |
+
}
|
89 |
+
|
90 |
+
$this->_options = FS_Option_Manager::get_manager( $id, $load, $this->_blog_id );
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Switch the context of the site level options manager.
|
95 |
+
*
|
96 |
+
* @author Vova Feldman (@svovaf)
|
97 |
+
* @since 2.0.0
|
98 |
+
*
|
99 |
+
* @param $blog_id
|
100 |
+
*/
|
101 |
+
function set_site_blog_context( $blog_id ) {
|
102 |
+
$this->_blog_id = $blog_id;
|
103 |
+
|
104 |
+
$this->_options = FS_Option_Manager::get_manager( $this->_id, false, $this->_blog_id );
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* @author Leo Fajardo (@leorw)
|
109 |
+
*
|
110 |
+
* @param string $option
|
111 |
+
* @param mixed $default
|
112 |
+
* @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::$_SITE_LEVEL_PARAMS).
|
113 |
+
*
|
114 |
+
* @return mixed
|
115 |
+
*/
|
116 |
+
function get_option( $option, $default = null, $network_level_or_blog_id = null ) {
|
117 |
+
if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
|
118 |
+
return $this->_network_options->get_option( $option, $default );
|
119 |
+
}
|
120 |
+
|
121 |
+
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
122 |
+
|
123 |
+
return $site_options->get_option( $option, $default );
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* @author Leo Fajardo (@leorw)
|
128 |
+
* @since 2.0.0
|
129 |
+
*
|
130 |
+
* @param string $option
|
131 |
+
* @param mixed $value
|
132 |
+
* @param bool $flush
|
133 |
+
* @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::$_SITE_LEVEL_PARAMS).
|
134 |
+
*/
|
135 |
+
function set_option( $option, $value, $flush = false, $network_level_or_blog_id = null ) {
|
136 |
+
if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
|
137 |
+
$this->_network_options->set_option( $option, $value, $flush );
|
138 |
+
} else {
|
139 |
+
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
140 |
+
$site_options->set_option( $option, $value, $flush );
|
141 |
+
}
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* @author Vova Feldman (@svovaf)
|
146 |
+
* @since 2.0.0
|
147 |
+
*
|
148 |
+
* @param string $option
|
149 |
+
* @param bool $flush
|
150 |
+
* @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::$_SITE_LEVEL_PARAMS).
|
151 |
+
*/
|
152 |
+
function unset_option( $option, $flush = false, $network_level_or_blog_id = null ) {
|
153 |
+
if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
|
154 |
+
$this->_network_options->unset_option( $option, $flush );
|
155 |
+
} else {
|
156 |
+
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
157 |
+
$site_options->unset_option( $option, $flush );
|
158 |
+
}
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* @author Leo Fajardo (@leorw)
|
163 |
+
* @since 2.0.0
|
164 |
+
*
|
165 |
+
* @param bool $flush
|
166 |
+
* @param bool $network_level
|
167 |
+
*/
|
168 |
+
function load( $flush = false, $network_level = true ) {
|
169 |
+
if ( $this->_is_multisite && $network_level ) {
|
170 |
+
$this->_network_options->load( $flush );
|
171 |
+
} else {
|
172 |
+
$this->_options->load( $flush );
|
173 |
+
}
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* @author Leo Fajardo (@leorw)
|
178 |
+
* @since 2.0.0
|
179 |
+
*
|
180 |
+
* @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`, store both network storage and the current context blog storage.
|
181 |
+
*/
|
182 |
+
function store( $network_level_or_blog_id = null ) {
|
183 |
+
if ( ! $this->_is_multisite ||
|
184 |
+
false === $network_level_or_blog_id ||
|
185 |
+
0 == $network_level_or_blog_id ||
|
186 |
+
is_null( $network_level_or_blog_id )
|
187 |
+
) {
|
188 |
+
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
189 |
+
$site_options->store();
|
190 |
+
}
|
191 |
+
|
192 |
+
if ( $this->_is_multisite &&
|
193 |
+
( is_null( $network_level_or_blog_id ) || true === $network_level_or_blog_id )
|
194 |
+
) {
|
195 |
+
$this->_network_options->store();
|
196 |
+
}
|
197 |
+
}
|
198 |
+
|
199 |
+
/**
|
200 |
+
* @author Vova Feldman (@svovaf)
|
201 |
+
* @since 2.0.0
|
202 |
+
*
|
203 |
+
* @param int|null|bool $network_level_or_blog_id
|
204 |
+
* @param bool $flush
|
205 |
+
*/
|
206 |
+
function clear( $network_level_or_blog_id = null, $flush = false ) {
|
207 |
+
if ( ! $this->_is_multisite ||
|
208 |
+
false === $network_level_or_blog_id ||
|
209 |
+
is_null( $network_level_or_blog_id ) ||
|
210 |
+
is_numeric( $network_level_or_blog_id )
|
211 |
+
) {
|
212 |
+
$site_options = $this->get_site_options( $network_level_or_blog_id );
|
213 |
+
$site_options->clear( $flush );
|
214 |
+
}
|
215 |
+
|
216 |
+
if ( $this->_is_multisite &&
|
217 |
+
( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
|
218 |
+
) {
|
219 |
+
$this->_network_options->clear( $flush );
|
220 |
+
}
|
221 |
+
}
|
222 |
+
|
223 |
+
/**
|
224 |
+
* Migration script to the new storage data structure that is network compatible.
|
225 |
+
*
|
226 |
+
* IMPORTANT:
|
227 |
+
* This method should be executed only after it is determined if this is a network
|
228 |
+
* level compatible product activation.
|
229 |
+
*
|
230 |
+
* @author Vova Feldman (@svovaf)
|
231 |
+
* @since 2.0.0
|
232 |
+
*
|
233 |
+
* @param int $blog_id
|
234 |
+
*/
|
235 |
+
function migrate_to_network( $blog_id = 0 ) {
|
236 |
+
if ( ! $this->_is_multisite ) {
|
237 |
+
return;
|
238 |
+
}
|
239 |
+
|
240 |
+
$updated = false;
|
241 |
+
|
242 |
+
$site_options = $this->get_site_options( $blog_id );
|
243 |
+
|
244 |
+
$keys = $site_options->get_options_keys();
|
245 |
+
|
246 |
+
foreach ( $keys as $option ) {
|
247 |
+
if ( $this->is_site_option( $option ) ||
|
248 |
+
// Don't move admin notices to the network storage.
|
249 |
+
in_array($option, array(
|
250 |
+
// Don't move admin notices to the network storage.
|
251 |
+
'admin_notices',
|
252 |
+
// Don't migrate the module specific data, it will be migrated by the FS_Storage.
|
253 |
+
'plugin_data',
|
254 |
+
'theme_data',
|
255 |
+
))
|
256 |
+
) {
|
257 |
+
continue;
|
258 |
+
}
|
259 |
+
|
260 |
+
$option_updated = false;
|
261 |
+
|
262 |
+
// Migrate option to the network storage.
|
263 |
+
$site_option = $site_options->get_option( $option );
|
264 |
+
|
265 |
+
if ( ! $this->_network_options->has_option( $option ) ) {
|
266 |
+
// Option not set on the network level, so just set it.
|
267 |
+
$this->_network_options->set_option( $option, $site_option, false );
|
268 |
+
|
269 |
+
$option_updated = true;
|
270 |
+
} else {
|
271 |
+
// Option already set on the network level, so we need to merge it inelegantly.
|
272 |
+
$network_option = $this->_network_options->get_option( $option );
|
273 |
+
|
274 |
+
if ( is_array( $network_option ) && is_array( $site_option ) ) {
|
275 |
+
// Option is an array.
|
276 |
+
foreach ( $site_option as $key => $value ) {
|
277 |
+
if ( ! isset( $network_option[ $key ] ) ) {
|
278 |
+
$network_option[ $key ] = $value;
|
279 |
+
|
280 |
+
$option_updated = true;
|
281 |
+
} else if ( is_array( $network_option[ $key ] ) && is_array( $value ) ) {
|
282 |
+
if ( empty( $network_option[ $key ] ) ) {
|
283 |
+
$network_option[ $key ] = $value;
|
284 |
+
|
285 |
+
$option_updated = true;
|
286 |
+
} else if ( empty( $value ) ) {
|
287 |
+
// Do nothing.
|
288 |
+
} else {
|
289 |
+
reset($value);
|
290 |
+
$first_key = key($value);
|
291 |
+
if ( $value[$first_key] instanceof FS_Entity ) {
|
292 |
+
// Merge entities by IDs.
|
293 |
+
$network_entities_ids = array();
|
294 |
+
foreach ( $network_option[ $key ] as $entity ) {
|
295 |
+
$network_entities_ids[ $entity->id ] = true;
|
296 |
+
}
|
297 |
+
|
298 |
+
foreach ( $value as $entity ) {
|
299 |
+
if ( ! isset( $network_entities_ids[ $entity->id ] ) ) {
|
300 |
+
$network_option[ $key ][] = $entity;
|
301 |
+
|
302 |
+
$option_updated = true;
|
303 |
+
}
|
304 |
+
}
|
305 |
+
}
|
306 |
+
}
|
307 |
+
}
|
308 |
+
}
|
309 |
+
}
|
310 |
+
|
311 |
+
if ( $option_updated ) {
|
312 |
+
$this->_network_options->set_option( $option, $network_option, false );
|
313 |
+
}
|
314 |
+
}
|
315 |
+
|
316 |
+
/**
|
317 |
+
* Remove the option from site level storage.
|
318 |
+
*
|
319 |
+
* IMPORTANT:
|
320 |
+
* The line below is intentionally commented since we want to preserve the option
|
321 |
+
* on the site storage level for "downgrade compatibility". Basically, if the user
|
322 |
+
* will downgrade to an older version of the plugin with the prev storage structure,
|
323 |
+
* it will continue working.
|
324 |
+
*
|
325 |
+
* @todo After a few releases we can remove this.
|
326 |
+
*/
|
327 |
+
// $site_options->unset_option($option, false);
|
328 |
+
|
329 |
+
if ( $option_updated ) {
|
330 |
+
$updated = true;
|
331 |
+
}
|
332 |
+
}
|
333 |
+
|
334 |
+
if ( ! $updated ) {
|
335 |
+
return;
|
336 |
+
}
|
337 |
+
|
338 |
+
// Update network level storage.
|
339 |
+
$this->_network_options->store();
|
340 |
+
// $site_options->store();
|
341 |
+
}
|
342 |
+
|
343 |
+
|
344 |
+
#--------------------------------------------------------------------------------
|
345 |
+
#region Helper Methods
|
346 |
+
#--------------------------------------------------------------------------------
|
347 |
+
|
348 |
+
/**
|
349 |
+
* We don't want to load the map right away since it's not even needed in a non-MS environment.
|
350 |
+
*
|
351 |
+
* @author Vova Feldman (@svovaf)
|
352 |
+
* @since 2.0.0
|
353 |
+
*/
|
354 |
+
private static function load_site_options_map() {
|
355 |
+
self::$_SITE_OPTIONS_MAP = array(
|
356 |
+
'sites' => true,
|
357 |
+
'theme_sites' => true,
|
358 |
+
'unique_id' => true,
|
359 |
+
'active_plugins' => true,
|
360 |
+
);
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
* @author Vova Feldman (@svovaf)
|
365 |
+
* @since 2.0.0
|
366 |
+
*
|
367 |
+
* @param string $option
|
368 |
+
*
|
369 |
+
* @return bool
|
370 |
+
*/
|
371 |
+
private function is_site_option( $option ) {
|
372 |
+
if ( WP_FS__ACCOUNTS_OPTION_NAME != $this->_id ) {
|
373 |
+
return false;
|
374 |
+
}
|
375 |
+
|
376 |
+
if ( ! isset( self::$_SITE_OPTIONS_MAP ) ) {
|
377 |
+
self::load_site_options_map();
|
378 |
+
}
|
379 |
+
|
380 |
+
return isset( self::$_SITE_OPTIONS_MAP[ $option ] );
|
381 |
+
}
|
382 |
+
|
383 |
+
/**
|
384 |
+
* @author Vova Feldman (@svovaf)
|
385 |
+
* @since 2.0.0
|
386 |
+
*
|
387 |
+
* @param int $blog_id
|
388 |
+
*
|
389 |
+
* @return FS_Option_Manager
|
390 |
+
*/
|
391 |
+
private function get_site_options( $blog_id = 0 ) {
|
392 |
+
if ( 0 == $blog_id || $blog_id == $this->_blog_id ) {
|
393 |
+
return $this->_options;
|
394 |
+
}
|
395 |
+
|
396 |
+
return FS_Option_Manager::get_manager( $this->_id, true, $blog_id );
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* Check if an option should be stored on the MS network storage.
|
401 |
+
*
|
402 |
+
* @author Vova Feldman (@svovaf)
|
403 |
+
* @since 2.0.0
|
404 |
+
*
|
405 |
+
* @param string $option
|
406 |
+
* @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::$_SITE_LEVEL_PARAMS).
|
407 |
+
*
|
408 |
+
* @return bool
|
409 |
+
*/
|
410 |
+
private function should_use_network_storage( $option, $network_level_or_blog_id = null ) {
|
411 |
+
if ( ! $this->_is_multisite ) {
|
412 |
+
// Not a multisite environment.
|
413 |
+
return false;
|
414 |
+
}
|
415 |
+
|
416 |
+
if ( is_numeric( $network_level_or_blog_id ) ) {
|
417 |
+
// Explicitly asked to use a specified blog storage.
|
418 |
+
return false;
|
419 |
+
}
|
420 |
+
|
421 |
+
if ( is_bool( $network_level_or_blog_id ) ) {
|
422 |
+
// Explicitly specified whether should use the network or blog level storage.
|
423 |
+
return $network_level_or_blog_id;
|
424 |
+
}
|
425 |
+
|
426 |
+
// Determine which storage to use based on the option.
|
427 |
+
return ! $this->is_site_option( $option );
|
428 |
+
}
|
429 |
+
|
430 |
+
#endregion
|
431 |
}
|
freemius/includes/class-fs-plugin-updater.php
CHANGED
@@ -1,1561 +1,1561 @@
|
|
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 1.0.4
|
7 |
-
*
|
8 |
-
* @link https://github.com/easydigitaldownloads/EDD-License-handler/blob/master/EDD_SL_Plugin_Updater.php
|
9 |
-
*/
|
10 |
-
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
class FS_Plugin_Updater {
|
16 |
-
|
17 |
-
/**
|
18 |
-
* @var Freemius
|
19 |
-
* @since 1.0.4
|
20 |
-
*/
|
21 |
-
private $_fs;
|
22 |
-
/**
|
23 |
-
* @var FS_Logger
|
24 |
-
* @since 1.0.4
|
25 |
-
*/
|
26 |
-
private $_logger;
|
27 |
-
/**
|
28 |
-
* @var object
|
29 |
-
* @since 1.1.8.1
|
30 |
-
*/
|
31 |
-
private $_update_details;
|
32 |
-
/**
|
33 |
-
* @var array
|
34 |
-
* @since 2.1.2
|
35 |
-
*/
|
36 |
-
private $_translation_updates;
|
37 |
-
|
38 |
-
private static $_upgrade_basename = null;
|
39 |
-
|
40 |
-
#--------------------------------------------------------------------------------
|
41 |
-
#region Singleton
|
42 |
-
#--------------------------------------------------------------------------------
|
43 |
-
|
44 |
-
/**
|
45 |
-
* @var FS_Plugin_Updater[]
|
46 |
-
* @since 2.0.0
|
47 |
-
*/
|
48 |
-
private static $_INSTANCES = array();
|
49 |
-
|
50 |
-
/**
|
51 |
-
* @param Freemius $freemius
|
52 |
-
*
|
53 |
-
* @return FS_Plugin_Updater
|
54 |
-
*/
|
55 |
-
static function instance( Freemius $freemius ) {
|
56 |
-
$key = $freemius->get_id();
|
57 |
-
|
58 |
-
if ( ! isset( self::$_INSTANCES[ $key ] ) ) {
|
59 |
-
self::$_INSTANCES[ $key ] = new self( $freemius );
|
60 |
-
}
|
61 |
-
|
62 |
-
return self::$_INSTANCES[ $key ];
|
63 |
-
}
|
64 |
-
|
65 |
-
#endregion
|
66 |
-
|
67 |
-
private function __construct( Freemius $freemius ) {
|
68 |
-
$this->_fs = $freemius;
|
69 |
-
|
70 |
-
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $freemius->get_slug() . '_updater', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
71 |
-
|
72 |
-
$this->filters();
|
73 |
-
}
|
74 |
-
|
75 |
-
/**
|
76 |
-
* Initiate required filters.
|
77 |
-
*
|
78 |
-
* @author Vova Feldman (@svovaf)
|
79 |
-
* @since 1.0.4
|
80 |
-
*/
|
81 |
-
private function filters() {
|
82 |
-
// Override request for plugin information
|
83 |
-
add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
|
84 |
-
|
85 |
-
$this->add_transient_filters();
|
86 |
-
|
87 |
-
/**
|
88 |
-
* If user has the premium plugin's code but do NOT have an active license,
|
89 |
-
* encourage him to upgrade by showing that there's a new release, but instead
|
90 |
-
* of showing an update link, show upgrade link to the pricing page.
|
91 |
-
*
|
92 |
-
* @since 1.1.6
|
93 |
-
*
|
94 |
-
*/
|
95 |
-
// WP 2.9+
|
96 |
-
add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
|
97 |
-
&$this,
|
98 |
-
'catch_plugin_update_row'
|
99 |
-
), 9 );
|
100 |
-
add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
|
101 |
-
&$this,
|
102 |
-
'edit_and_echo_plugin_update_row'
|
103 |
-
), 11, 2 );
|
104 |
-
|
105 |
-
if ( ! $this->_fs->has_any_active_valid_license() ) {
|
106 |
-
add_action( 'admin_head', array( &$this, 'catch_plugin_information_dialog_contents' ) );
|
107 |
-
}
|
108 |
-
|
109 |
-
if ( ! WP_FS__IS_PRODUCTION_MODE ) {
|
110 |
-
add_filter( 'http_request_host_is_external', array(
|
111 |
-
$this,
|
112 |
-
'http_request_host_is_external_filter'
|
113 |
-
), 10, 3 );
|
114 |
-
}
|
115 |
-
|
116 |
-
if ( $this->_fs->is_premium() ) {
|
117 |
-
if ( ! $this->is_correct_folder_name() ) {
|
118 |
-
add_filter( 'upgrader_post_install', array( &$this, '_maybe_update_folder_name' ), 10, 3 );
|
119 |
-
}
|
120 |
-
|
121 |
-
add_filter( 'upgrader_pre_install', array( 'FS_Plugin_Updater', '_store_basename_for_source_adjustment' ), 1, 2 );
|
122 |
-
add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 );
|
123 |
-
|
124 |
-
if ( ! $this->_fs->has_any_active_valid_license() ) {
|
125 |
-
add_filter( 'wp_prepare_themes_for_js', array( &$this, 'change_theme_update_info_html' ), 10, 1 );
|
126 |
-
}
|
127 |
-
}
|
128 |
-
}
|
129 |
-
|
130 |
-
/**
|
131 |
-
* @author Leo Fajardo (@leorw)
|
132 |
-
* @since 2.1.4
|
133 |
-
*/
|
134 |
-
function catch_plugin_information_dialog_contents() {
|
135 |
-
if (
|
136 |
-
'plugin-information' !== fs_request_get( 'tab', false ) ||
|
137 |
-
$this->_fs->get_slug() !== fs_request_get( 'plugin', false )
|
138 |
-
) {
|
139 |
-
return;
|
140 |
-
}
|
141 |
-
|
142 |
-
add_action( 'admin_footer', array( &$this, 'edit_and_echo_plugin_information_dialog_contents' ), 0, 1 );
|
143 |
-
|
144 |
-
ob_start();
|
145 |
-
}
|
146 |
-
|
147 |
-
/**
|
148 |
-
* @author Leo Fajardo (@leorw)
|
149 |
-
* @since 2.1.4
|
150 |
-
*
|
151 |
-
* @param string $hook_suffix
|
152 |
-
*/
|
153 |
-
function edit_and_echo_plugin_information_dialog_contents( $hook_suffix ) {
|
154 |
-
if (
|
155 |
-
'plugin-information' !== fs_request_get( 'tab', false ) ||
|
156 |
-
$this->_fs->get_slug() !== fs_request_get( 'plugin', false )
|
157 |
-
) {
|
158 |
-
return;
|
159 |
-
}
|
160 |
-
|
161 |
-
$license = $this->_fs->_get_license();
|
162 |
-
|
163 |
-
$subscription = ( is_object( $license ) && ! $license->is_lifetime() ) ?
|
164 |
-
$this->_fs->_get_subscription( $license->id ) :
|
165 |
-
null;
|
166 |
-
|
167 |
-
$contents = ob_get_clean();
|
168 |
-
|
169 |
-
$update_button_id_attribute_pos = strpos( $contents, 'id="plugin_update_from_iframe"' );
|
170 |
-
|
171 |
-
if ( false !== $update_button_id_attribute_pos ) {
|
172 |
-
$update_button_start_pos = strrpos(
|
173 |
-
substr( $contents, 0, $update_button_id_attribute_pos ),
|
174 |
-
'<a'
|
175 |
-
);
|
176 |
-
|
177 |
-
$update_button_end_pos = ( strpos( $contents, '</a>', $update_button_id_attribute_pos ) + strlen( '</a>' ) );
|
178 |
-
|
179 |
-
/**
|
180 |
-
* The part of the contents without the update button.
|
181 |
-
*
|
182 |
-
* @author Leo Fajardo (@leorw)
|
183 |
-
* @since 2.2.5
|
184 |
-
*/
|
185 |
-
$modified_contents = substr( $contents, 0, $update_button_start_pos );
|
186 |
-
|
187 |
-
$update_button = substr( $contents, $update_button_start_pos, ( $update_button_end_pos - $update_button_start_pos ) );
|
188 |
-
|
189 |
-
/**
|
190 |
-
* Replace the plugin information dialog's "Install Update Now" button's text and URL. If there's a license,
|
191 |
-
* the text will be "Renew license" and will link to the checkout page with the license's billing cycle
|
192 |
-
* and quota. If there's no license, the text will be "Buy license" and will link to the pricing page.
|
193 |
-
*/
|
194 |
-
$update_button = preg_replace(
|
195 |
-
'/(\<a.+)(id="plugin_update_from_iframe")(.+href=")([^\s]+)(".*\>)(.+)(\<\/a>)/is',
|
196 |
-
is_object( $license ) ?
|
197 |
-
sprintf(
|
198 |
-
'$1$3%s$5%s$7',
|
199 |
-
$this->_fs->checkout_url(
|
200 |
-
is_object( $subscription ) ?
|
201 |
-
( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) :
|
202 |
-
WP_FS__PERIOD_LIFETIME,
|
203 |
-
false,
|
204 |
-
array( 'licenses' => $license->quota )
|
205 |
-
),
|
206 |
-
fs_text_inline( 'Renew license', 'renew-license', $this->_fs->get_slug() )
|
207 |
-
) :
|
208 |
-
sprintf(
|
209 |
-
'$1$3%s$5%s$7',
|
210 |
-
$this->_fs->pricing_url(),
|
211 |
-
fs_text_inline( 'Buy license', 'buy-license', $this->_fs->get_slug() )
|
212 |
-
),
|
213 |
-
$update_button
|
214 |
-
);
|
215 |
-
|
216 |
-
/**
|
217 |
-
* Append the modified button.
|
218 |
-
*
|
219 |
-
* @author Leo Fajardo (@leorw)
|
220 |
-
* @since 2.2.5
|
221 |
-
*/
|
222 |
-
$modified_contents .= $update_button;
|
223 |
-
|
224 |
-
/**
|
225 |
-
* Append the remaining part of the contents after the update button.
|
226 |
-
*
|
227 |
-
* @author Leo Fajardo (@leorw)
|
228 |
-
* @since 2.2.5
|
229 |
-
*/
|
230 |
-
$modified_contents .= substr( $contents, $update_button_end_pos );
|
231 |
-
|
232 |
-
$contents = $modified_contents;
|
233 |
-
}
|
234 |
-
|
235 |
-
echo $contents;
|
236 |
-
}
|
237 |
-
|
238 |
-
/**
|
239 |
-
* @author Vova Feldman (@svovaf)
|
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;
|
247 |
-
}
|
248 |
-
|
249 |
-
add_filter( 'pre_set_site_transient_update_plugins', array(
|
250 |
-
&$this,
|
251 |
-
'pre_set_site_transient_update_plugins_filter'
|
252 |
-
) );
|
253 |
-
|
254 |
-
add_filter( 'pre_set_site_transient_update_themes', array(
|
255 |
-
&$this,
|
256 |
-
'pre_set_site_transient_update_plugins_filter'
|
257 |
-
) );
|
258 |
-
}
|
259 |
-
|
260 |
-
/**
|
261 |
-
* @author Vova Feldman (@svovaf)
|
262 |
-
* @since 2.0.0
|
263 |
-
*/
|
264 |
-
private function remove_transient_filters() {
|
265 |
-
remove_filter( 'pre_set_site_transient_update_plugins', array(
|
266 |
-
&$this,
|
267 |
-
'pre_set_site_transient_update_plugins_filter'
|
268 |
-
) );
|
269 |
-
|
270 |
-
remove_filter( 'pre_set_site_transient_update_themes', array(
|
271 |
-
&$this,
|
272 |
-
'pre_set_site_transient_update_plugins_filter'
|
273 |
-
) );
|
274 |
-
}
|
275 |
-
|
276 |
-
/**
|
277 |
-
* Capture plugin update row by turning output buffering.
|
278 |
-
*
|
279 |
-
* @author Vova Feldman (@svovaf)
|
280 |
-
* @since 1.1.6
|
281 |
-
*/
|
282 |
-
function catch_plugin_update_row() {
|
283 |
-
ob_start();
|
284 |
-
}
|
285 |
-
|
286 |
-
/**
|
287 |
-
* Overrides default update message format with "renew your license" message.
|
288 |
-
*
|
289 |
-
* @author Vova Feldman (@svovaf)
|
290 |
-
* @since 1.1.6
|
291 |
-
*
|
292 |
-
* @param string $file
|
293 |
-
* @param array $plugin_data
|
294 |
-
*/
|
295 |
-
function edit_and_echo_plugin_update_row( $file, $plugin_data ) {
|
296 |
-
$plugin_update_row = ob_get_clean();
|
297 |
-
|
298 |
-
$current = get_site_transient( 'update_plugins' );
|
299 |
-
if ( ! isset( $current->response[ $file ] ) ) {
|
300 |
-
echo $plugin_update_row;
|
301 |
-
|
302 |
-
return;
|
303 |
-
}
|
304 |
-
|
305 |
-
$r = $current->response[ $file ];
|
306 |
-
|
307 |
-
$has_beta_update = $this->_fs->has_beta_update();
|
308 |
-
|
309 |
-
if ( $this->_fs->has_any_active_valid_license() ) {
|
310 |
-
if ( $has_beta_update ) {
|
311 |
-
/**
|
312 |
-
* Turn the "new version" text into "new Beta version".
|
313 |
-
*
|
314 |
-
* Sample input:
|
315 |
-
* There is a new version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
|
316 |
-
* Output:
|
317 |
-
* There is a new Beta version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
|
318 |
-
*
|
319 |
-
* @author Leo Fajardo (@leorw)
|
320 |
-
* @since 2.3.0
|
321 |
-
*/
|
322 |
-
$plugin_update_row = preg_replace(
|
323 |
-
'/(\<div.+>)(.+)(\<a.+href="([^\s]+)"([^\<]+)\>.+\<a.+)(\<\/div\>)/is',
|
324 |
-
(
|
325 |
-
'$1' .
|
326 |
-
sprintf(
|
327 |
-
fs_text_inline( 'There is a %s of %s available.', 'new-version-available', $this->_fs->get_slug() ),
|
328 |
-
$has_beta_update ?
|
329 |
-
fs_text_inline( 'new Beta version', 'new-beta-version', $this->_fs->get_slug() ) :
|
330 |
-
fs_text_inline( 'new version', 'new-version', $this->_fs->get_slug() ),
|
331 |
-
$this->_fs->get_plugin_title()
|
332 |
-
) .
|
333 |
-
' ' .
|
334 |
-
'$3' .
|
335 |
-
'$6'
|
336 |
-
),
|
337 |
-
$plugin_update_row
|
338 |
-
);
|
339 |
-
}
|
340 |
-
} else {
|
341 |
-
/**
|
342 |
-
* Turn the "new version" text into a link that opens the plugin information dialog when clicked and
|
343 |
-
* make the "View version x details" text link to the checkout page instead of opening the plugin
|
344 |
-
* information dialog when clicked.
|
345 |
-
*
|
346 |
-
* Sample input:
|
347 |
-
* There is a new version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
|
348 |
-
* Output:
|
349 |
-
* There is a <a href="...>new version</a> of Awesome Plugin available. <a href="...>Buy a license now</a> to access version x.y.z security & feature updates, and support.
|
350 |
-
* OR
|
351 |
-
* There is a <a href="...>new Beta version</a> of Awesome Plugin available. <a href="...>Buy a license now</a> to access version x.y.z security & feature updates, and support.
|
352 |
-
*
|
353 |
-
* @author Leo Fajardo (@leorw)
|
354 |
-
*/
|
355 |
-
$plugin_update_row = preg_replace(
|
356 |
-
'/(\<div.+>)(.+)(\<a.+href="([^\s]+)"([^\<]+)\>.+\<a.+)(\<\/div\>)/is',
|
357 |
-
(
|
358 |
-
'$1' .
|
359 |
-
sprintf(
|
360 |
-
fs_text_inline( 'There is a %s of %s available.', 'new-version-available', $this->_fs->get_slug() ),
|
361 |
-
sprintf(
|
362 |
-
'<a href="$4"%s>%s</a>',
|
363 |
-
'$5',
|
364 |
-
$has_beta_update ?
|
365 |
-
fs_text_inline( 'new Beta version', 'new-beta-version', $this->_fs->get_slug() ) :
|
366 |
-
fs_text_inline( 'new version', 'new-version', $this->_fs->get_slug() )
|
367 |
-
),
|
368 |
-
$this->_fs->get_plugin_title()
|
369 |
-
) .
|
370 |
-
' ' .
|
371 |
-
$this->_fs->version_upgrade_checkout_link( $r->new_version ) .
|
372 |
-
'$6'
|
373 |
-
),
|
374 |
-
$plugin_update_row
|
375 |
-
);
|
376 |
-
}
|
377 |
-
|
378 |
-
if (
|
379 |
-
$this->_fs->is_plugin() &&
|
380 |
-
isset( $r->upgrade_notice ) &&
|
381 |
-
strlen( trim( $r->upgrade_notice ) ) > 0
|
382 |
-
) {
|
383 |
-
$slug = $this->_fs->get_slug();
|
384 |
-
|
385 |
-
$upgrade_notice_html = sprintf(
|
386 |
-
'<p class="notice fs-upgrade-notice fs-slug-%1$s fs-type-%2$s" data-slug="%1$s" data-type="%2$s"><strong>%3$s</strong> %4$s</p>',
|
387 |
-
$slug,
|
388 |
-
$this->_fs->get_module_type(),
|
389 |
-
fs_text_inline( 'Important Upgrade Notice:', 'upgrade_notice', $slug ),
|
390 |
-
esc_html( $r->upgrade_notice )
|
391 |
-
);
|
392 |
-
|
393 |
-
$plugin_update_row = str_replace( '</div>', '</div>' . $upgrade_notice_html, $plugin_update_row );
|
394 |
-
}
|
395 |
-
|
396 |
-
echo $plugin_update_row;
|
397 |
-
}
|
398 |
-
|
399 |
-
/**
|
400 |
-
* @author Leo Fajardo (@leorw)
|
401 |
-
* @since 2.0.2
|
402 |
-
*
|
403 |
-
* @param array $prepared_themes
|
404 |
-
*
|
405 |
-
* @return array
|
406 |
-
*/
|
407 |
-
function change_theme_update_info_html( $prepared_themes ) {
|
408 |
-
$theme_basename = $this->_fs->get_plugin_basename();
|
409 |
-
|
410 |
-
if ( ! isset( $prepared_themes[ $theme_basename ] ) ) {
|
411 |
-
return $prepared_themes;
|
412 |
-
}
|
413 |
-
|
414 |
-
$themes_update = get_site_transient( 'update_themes' );
|
415 |
-
if ( ! isset( $themes_update->response[ $theme_basename ] ) ||
|
416 |
-
empty( $themes_update->response[ $theme_basename ]['package'] )
|
417 |
-
) {
|
418 |
-
return $prepared_themes;
|
419 |
-
}
|
420 |
-
|
421 |
-
$prepared_themes[ $theme_basename ]['update'] = preg_replace(
|
422 |
-
'/(\<p.+>)(.+)(\<a.+\<a.+)\.(.+\<\/p\>)/is',
|
423 |
-
'$1 $2 ' . $this->_fs->version_upgrade_checkout_link( $themes_update->response[ $theme_basename ]['new_version'] ) .
|
424 |
-
'$4',
|
425 |
-
$prepared_themes[ $theme_basename ]['update']
|
426 |
-
);
|
427 |
-
|
428 |
-
// Set to false to prevent the "Update now" link for the context theme from being shown on the "Themes" page.
|
429 |
-
$prepared_themes[ $theme_basename ]['hasPackage'] = false;
|
430 |
-
|
431 |
-
return $prepared_themes;
|
432 |
-
}
|
433 |
-
|
434 |
-
/**
|
435 |
-
* Since WP version 3.6, a new security feature was added that denies access to repository with a local ip.
|
436 |
-
* During development mode we want to be able updating plugin versions via our localhost repository. This
|
437 |
-
* filter white-list all domains including "api.freemius".
|
438 |
-
*
|
439 |
-
* @link http://www.emanueletessore.com/wordpress-download-failed-valid-url-provided/
|
440 |
-
*
|
441 |
-
* @author Vova Feldman (@svovaf)
|
442 |
-
* @since 1.0.4
|
443 |
-
*
|
444 |
-
* @param bool $allow
|
445 |
-
* @param string $host
|
446 |
-
* @param string $url
|
447 |
-
*
|
448 |
-
* @return bool
|
449 |
-
*/
|
450 |
-
function http_request_host_is_external_filter( $allow, $host, $url ) {
|
451 |
-
return ( false !== strpos( $host, 'freemius' ) ) ? true : $allow;
|
452 |
-
}
|
453 |
-
|
454 |
-
/**
|
455 |
-
* Check for Updates at the defined API endpoint and modify the update array.
|
456 |
-
*
|
457 |
-
* This function dives into the update api just when WordPress creates its update array,
|
458 |
-
* then adds a custom API call and injects the custom plugin data retrieved from the API.
|
459 |
-
* It is reassembled from parts of the native WordPress plugin update code.
|
460 |
-
* See wp-includes/update.php line 121 for the original wp_update_plugins() function.
|
461 |
-
*
|
462 |
-
* @author Vova Feldman (@svovaf)
|
463 |
-
* @since 1.0.4
|
464 |
-
*
|
465 |
-
* @uses FS_Api
|
466 |
-
*
|
467 |
-
* @param object $transient_data Update array build by WordPress.
|
468 |
-
*
|
469 |
-
* @return object Modified update array with custom plugin data.
|
470 |
-
*/
|
471 |
-
function pre_set_site_transient_update_plugins_filter( $transient_data ) {
|
472 |
-
$this->_logger->entrance();
|
473 |
-
|
474 |
-
/**
|
475 |
-
* "plugins" or "themes".
|
476 |
-
*
|
477 |
-
* @author Leo Fajardo (@leorw)
|
478 |
-
* @since 1.2.2
|
479 |
-
*/
|
480 |
-
$module_type = $this->_fs->get_module_type() . 's';
|
481 |
-
|
482 |
-
/**
|
483 |
-
* Ensure that we don't mix plugins update info with themes update info.
|
484 |
-
*
|
485 |
-
* @author Leo Fajardo (@leorw)
|
486 |
-
* @since 1.2.2
|
487 |
-
*/
|
488 |
-
if ( "pre_set_site_transient_update_{$module_type}" !== current_filter() ) {
|
489 |
-
return $transient_data;
|
490 |
-
}
|
491 |
-
|
492 |
-
if ( empty( $transient_data ) ||
|
493 |
-
defined( 'WP_FS__UNINSTALL_MODE' )
|
494 |
-
) {
|
495 |
-
return $transient_data;
|
496 |
-
}
|
497 |
-
|
498 |
-
global $wp_current_filter;
|
499 |
-
|
500 |
-
$current_plugin_version = $this->_fs->get_plugin_version();
|
501 |
-
|
502 |
-
if ( ! empty( $wp_current_filter ) && 'upgrader_process_complete' === $wp_current_filter[0] ) {
|
503 |
-
if (
|
504 |
-
is_null( $this->_update_details ) ||
|
505 |
-
( is_object( $this->_update_details ) && $this->_update_details->new_version !== $current_plugin_version )
|
506 |
-
) {
|
507 |
-
/**
|
508 |
-
* After an update, clear the stored update details and reparse the plugin's main file in order to get
|
509 |
-
* the updated version's information and prevent the previous update information from showing up on the
|
510 |
-
* updates page.
|
511 |
-
*
|
512 |
-
* @author Leo Fajardo (@leorw)
|
513 |
-
* @since 2.3.1
|
514 |
-
*/
|
515 |
-
$this->_update_details = null;
|
516 |
-
$current_plugin_version = $this->_fs->get_plugin_version( true );
|
517 |
-
}
|
518 |
-
}
|
519 |
-
|
520 |
-
if ( ! isset( $this->_update_details ) ) {
|
521 |
-
// Get plugin's newest update.
|
522 |
-
$new_version = $this->_fs->get_update(
|
523 |
-
false,
|
524 |
-
fs_request_get_bool( 'force-check' ),
|
525 |
-
WP_FS__TIME_24_HOURS_IN_SEC / 24,
|
526 |
-
$current_plugin_version
|
527 |
-
);
|
528 |
-
|
529 |
-
$this->_update_details = false;
|
530 |
-
|
531 |
-
if ( is_object( $new_version ) && $this->is_new_version_premium( $new_version ) ) {
|
532 |
-
$this->_logger->log( 'Found newer plugin version ' . $new_version->version );
|
533 |
-
|
534 |
-
/**
|
535 |
-
* Cache plugin details locally since set_site_transient( 'update_plugins' )
|
536 |
-
* called multiple times and the non wp.org plugins are filtered after the
|
537 |
-
* call to .org.
|
538 |
-
*
|
539 |
-
* @since 1.1.8.1
|
540 |
-
*/
|
541 |
-
$this->_update_details = $this->get_update_details( $new_version );
|
542 |
-
}
|
543 |
-
}
|
544 |
-
|
545 |
-
// Alias.
|
546 |
-
$basename = $this->_fs->premium_plugin_basename();
|
547 |
-
|
548 |
-
if ( is_object( $this->_update_details ) ) {
|
549 |
-
if ( isset( $transient_data->no_update ) ) {
|
550 |
-
unset( $transient_data->no_update[ $basename ] );
|
551 |
-
}
|
552 |
-
|
553 |
-
if ( ! isset( $transient_data->response ) ) {
|
554 |
-
$transient_data->response = array();
|
555 |
-
}
|
556 |
-
|
557 |
-
// Add plugin to transient data.
|
558 |
-
$transient_data->response[ $basename ] = $this->_fs->is_plugin() ?
|
559 |
-
$this->_update_details :
|
560 |
-
(array) $this->_update_details;
|
561 |
-
} else {
|
562 |
-
if ( isset( $transient_data->response ) ) {
|
563 |
-
/**
|
564 |
-
* Ensure that there's no update data for the plugin to prevent upgrading the premium version to the latest free version.
|
565 |
-
*
|
566 |
-
* @author Leo Fajardo (@leorw)
|
567 |
-
* @since 2.3.0
|
568 |
-
*/
|
569 |
-
unset( $transient_data->response[ $basename ] );
|
570 |
-
}
|
571 |
-
|
572 |
-
if ( ! isset( $transient_data->no_update ) ) {
|
573 |
-
$transient_data->no_update = array();
|
574 |
-
}
|
575 |
-
|
576 |
-
/**
|
577 |
-
* Add product to no_update transient data to properly integrate with WP 5.5 auto-updates UI.
|
578 |
-
*
|
579 |
-
* @since 2.4.1
|
580 |
-
* @link https://make.wordpress.org/core/2020/07/30/recommended-usage-of-the-updates-api-to-support-the-auto-updates-ui-for-plugins-and-themes-in-wordpress-5-5/
|
581 |
-
*/
|
582 |
-
$transient_data->no_update[ $basename ] = $this->_fs->is_plugin() ?
|
583 |
-
(object) array(
|
584 |
-
'id' => $basename,
|
585 |
-
'slug' => $this->_fs->get_slug(),
|
586 |
-
'plugin' => $basename,
|
587 |
-
'new_version' => $this->_fs->get_plugin_version(),
|
588 |
-
'url' => '',
|
589 |
-
'package' => '',
|
590 |
-
'icons' => array(),
|
591 |
-
'banners' => array(),
|
592 |
-
'banners_rtl' => array(),
|
593 |
-
'tested' => '',
|
594 |
-
'requires_php' => '',
|
595 |
-
'compatibility' => new stdClass(),
|
596 |
-
) :
|
597 |
-
array(
|
598 |
-
'theme' => $basename,
|
599 |
-
'new_version' => $this->_fs->get_plugin_version(),
|
600 |
-
'url' => '',
|
601 |
-
'package' => '',
|
602 |
-
'requires' => '',
|
603 |
-
'requires_php' => '',
|
604 |
-
);
|
605 |
-
}
|
606 |
-
|
607 |
-
$slug = $this->_fs->get_slug();
|
608 |
-
|
609 |
-
if ( $this->_fs->is_org_repo_compliant() && $this->_fs->is_freemium() ) {
|
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 |
-
|
621 |
-
if ( ! empty( $this->_translation_updates ) ) {
|
622 |
-
$all_translation_updates = ( isset( $transient_data->translations ) && is_array( $transient_data->translations ) ) ?
|
623 |
-
$transient_data->translations :
|
624 |
-
array();
|
625 |
-
|
626 |
-
$current_plugin_translation_updates_map = array();
|
627 |
-
foreach ( $all_translation_updates as $key => $translation_update ) {
|
628 |
-
if ( $module_type === ( $translation_update['type'] . 's' ) && $slug === $translation_update['slug'] ) {
|
629 |
-
$current_plugin_translation_updates_map[ $translation_update['language'] ] = $translation_update;
|
630 |
-
unset( $all_translation_updates[ $key ] );
|
631 |
-
}
|
632 |
-
}
|
633 |
-
|
634 |
-
foreach ( $this->_translation_updates as $translation_update ) {
|
635 |
-
$lang = $translation_update['language'];
|
636 |
-
if ( ! isset( $current_plugin_translation_updates_map[ $lang ] ) ||
|
637 |
-
version_compare( $translation_update['version'], $current_plugin_translation_updates_map[ $lang ]['version'], '>' )
|
638 |
-
) {
|
639 |
-
$current_plugin_translation_updates_map[ $lang ] = $translation_update;
|
640 |
-
}
|
641 |
-
}
|
642 |
-
|
643 |
-
$transient_data->translations = array_merge( $all_translation_updates, array_values( $current_plugin_translation_updates_map ) );
|
644 |
-
}
|
645 |
-
}
|
646 |
-
|
647 |
-
return $transient_data;
|
648 |
-
}
|
649 |
-
|
650 |
-
/**
|
651 |
-
* Get module's required data for the updates mechanism.
|
652 |
-
*
|
653 |
-
* @author Vova Feldman (@svovaf)
|
654 |
-
* @since 2.0.0
|
655 |
-
*
|
656 |
-
* @param \FS_Plugin_Tag $new_version
|
657 |
-
*
|
658 |
-
* @return object
|
659 |
-
*/
|
660 |
-
function get_update_details( FS_Plugin_Tag $new_version ) {
|
661 |
-
$update = new stdClass();
|
662 |
-
$update->slug = $this->_fs->get_slug();
|
663 |
-
$update->new_version = $new_version->version;
|
664 |
-
$update->url = WP_FS__ADDRESS;
|
665 |
-
$update->package = $new_version->url;
|
666 |
-
$update->tested = $new_version->tested_up_to_version;
|
667 |
-
$update->requires = $new_version->requires_platform_version;
|
668 |
-
|
669 |
-
$icon = $this->_fs->get_local_icon_url();
|
670 |
-
|
671 |
-
if ( ! empty( $icon ) ) {
|
672 |
-
$update->icons = array(
|
673 |
-
// '1x' => $icon,
|
674 |
-
// '2x' => $icon,
|
675 |
-
'default' => $icon,
|
676 |
-
);
|
677 |
-
}
|
678 |
-
|
679 |
-
if ( $this->_fs->is_premium() ) {
|
680 |
-
$latest_tag = $this->_fs->_fetch_latest_version( $this->_fs->get_id(), false );
|
681 |
-
|
682 |
-
if (
|
683 |
-
isset( $latest_tag->readme ) &&
|
684 |
-
isset( $latest_tag->readme->upgrade_notice ) &&
|
685 |
-
! empty( $latest_tag->readme->upgrade_notice )
|
686 |
-
) {
|
687 |
-
$update->upgrade_notice = $latest_tag->readme->upgrade_notice;
|
688 |
-
}
|
689 |
-
}
|
690 |
-
|
691 |
-
$update->{$this->_fs->get_module_type()} = $this->_fs->get_plugin_basename();
|
692 |
-
|
693 |
-
return $update;
|
694 |
-
}
|
695 |
-
|
696 |
-
/**
|
697 |
-
* @author Leo Fajardo (@leorw)
|
698 |
-
* @since 2.3.0
|
699 |
-
*
|
700 |
-
* @param FS_Plugin_Tag $new_version
|
701 |
-
*
|
702 |
-
* @return bool
|
703 |
-
*/
|
704 |
-
private function is_new_version_premium( FS_Plugin_Tag $new_version ) {
|
705 |
-
$query_str = parse_url( $new_version->url, PHP_URL_QUERY );
|
706 |
-
if ( empty( $query_str ) ) {
|
707 |
-
return false;
|
708 |
-
}
|
709 |
-
|
710 |
-
parse_str( $query_str, $params );
|
711 |
-
|
712 |
-
return ( isset( $params['is_premium'] ) && 'true' == $params['is_premium'] );
|
713 |
-
}
|
714 |
-
|
715 |
-
/**
|
716 |
-
* Update the updates transient with the module's update information.
|
717 |
-
*
|
718 |
-
* This method is required for multisite environment.
|
719 |
-
* If a module is site activated (not network) and not on the main site,
|
720 |
-
* the module will NOT be executed on the network level, therefore, the
|
721 |
-
* custom updates logic will not be executed as well, so unless we force
|
722 |
-
* the injection of the update into the updates transient, premium updates
|
723 |
-
* will not work.
|
724 |
-
*
|
725 |
-
* @author Vova Feldman (@svovaf)
|
726 |
-
* @since 2.0.0
|
727 |
-
*
|
728 |
-
* @param \FS_Plugin_Tag $new_version
|
729 |
-
*/
|
730 |
-
function set_update_data( FS_Plugin_Tag $new_version ) {
|
731 |
-
$this->_logger->entrance();
|
732 |
-
|
733 |
-
if ( ! $this->is_new_version_premium( $new_version ) ) {
|
734 |
-
return;
|
735 |
-
}
|
736 |
-
|
737 |
-
$transient_key = "update_{$this->_fs->get_module_type()}s";
|
738 |
-
|
739 |
-
$transient_data = get_site_transient( $transient_key );
|
740 |
-
|
741 |
-
$transient_data = is_object( $transient_data ) ?
|
742 |
-
$transient_data :
|
743 |
-
new stdClass();
|
744 |
-
|
745 |
-
// Alias.
|
746 |
-
$basename = $this->_fs->get_plugin_basename();
|
747 |
-
$is_plugin = $this->_fs->is_plugin();
|
748 |
-
|
749 |
-
if ( ! isset( $transient_data->response ) ||
|
750 |
-
! is_array( $transient_data->response )
|
751 |
-
) {
|
752 |
-
$transient_data->response = array();
|
753 |
-
} else if ( ! empty( $transient_data->response[ $basename ] ) ) {
|
754 |
-
$version = $is_plugin ?
|
755 |
-
( ! empty( $transient_data->response[ $basename ]->new_version ) ?
|
756 |
-
$transient_data->response[ $basename ]->new_version :
|
757 |
-
null
|
758 |
-
) : ( ! empty( $transient_data->response[ $basename ]['new_version'] ) ?
|
759 |
-
$transient_data->response[ $basename ]['new_version'] :
|
760 |
-
null
|
761 |
-
);
|
762 |
-
|
763 |
-
if ( $version == $new_version->version ) {
|
764 |
-
// The update data is already set.
|
765 |
-
return;
|
766 |
-
}
|
767 |
-
}
|
768 |
-
|
769 |
-
// Remove the added filters.
|
770 |
-
$this->remove_transient_filters();
|
771 |
-
|
772 |
-
$this->_update_details = $this->get_update_details( $new_version );
|
773 |
-
|
774 |
-
// Set update data in transient.
|
775 |
-
$transient_data->response[ $basename ] = $is_plugin ?
|
776 |
-
$this->_update_details :
|
777 |
-
(array) $this->_update_details;
|
778 |
-
|
779 |
-
if ( ! isset( $transient_data->checked ) ||
|
780 |
-
! is_array( $transient_data->checked )
|
781 |
-
) {
|
782 |
-
$transient_data->checked = array();
|
783 |
-
}
|
784 |
-
|
785 |
-
// Flag the module as if it was already checked.
|
786 |
-
$transient_data->checked[ $basename ] = $this->_fs->get_plugin_version();
|
787 |
-
$transient_data->last_checked = time();
|
788 |
-
|
789 |
-
set_site_transient( $transient_key, $transient_data );
|
790 |
-
|
791 |
-
$this->add_transient_filters();
|
792 |
-
}
|
793 |
-
|
794 |
-
/**
|
795 |
-
* @author Leo Fajardo (@leorw)
|
796 |
-
* @since 2.0.2
|
797 |
-
*/
|
798 |
-
function delete_update_data() {
|
799 |
-
$this->_logger->entrance();
|
800 |
-
|
801 |
-
$transient_key = "update_{$this->_fs->get_module_type()}s";
|
802 |
-
|
803 |
-
$transient_data = get_site_transient( $transient_key );
|
804 |
-
|
805 |
-
// Alias
|
806 |
-
$basename = $this->_fs->get_plugin_basename();
|
807 |
-
|
808 |
-
if ( ! is_object( $transient_data ) ||
|
809 |
-
! isset( $transient_data->response ) ||
|
810 |
-
! is_array( $transient_data->response ) ||
|
811 |
-
empty( $transient_data->response[ $basename ] )
|
812 |
-
) {
|
813 |
-
return;
|
814 |
-
}
|
815 |
-
|
816 |
-
unset( $transient_data->response[ $basename ] );
|
817 |
-
|
818 |
-
// Remove the added filters.
|
819 |
-
$this->remove_transient_filters();
|
820 |
-
|
821 |
-
set_site_transient( $transient_key, $transient_data );
|
822 |
-
|
823 |
-
$this->add_transient_filters();
|
824 |
-
}
|
825 |
-
|
826 |
-
/**
|
827 |
-
* Try to fetch plugin's info from .org repository.
|
828 |
-
*
|
829 |
-
* @author Vova Feldman (@svovaf)
|
830 |
-
* @since 1.0.5
|
831 |
-
*
|
832 |
-
* @param string $action
|
833 |
-
* @param object $args
|
834 |
-
*
|
835 |
-
* @return bool|mixed
|
836 |
-
*/
|
837 |
-
static function _fetch_plugin_info_from_repository( $action, $args ) {
|
838 |
-
$url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
|
839 |
-
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
|
840 |
-
$url = set_url_scheme( $url, 'https' );
|
841 |
-
}
|
842 |
-
|
843 |
-
$args = array(
|
844 |
-
'timeout' => 15,
|
845 |
-
'body' => array(
|
846 |
-
'action' => $action,
|
847 |
-
'request' => serialize( $args )
|
848 |
-
)
|
849 |
-
);
|
850 |
-
|
851 |
-
$request = wp_remote_post( $url, $args );
|
852 |
-
|
853 |
-
if ( is_wp_error( $request ) ) {
|
854 |
-
return false;
|
855 |
-
}
|
856 |
-
|
857 |
-
$res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
|
858 |
-
|
859 |
-
if ( ! is_object( $res ) && ! is_array( $res ) ) {
|
860 |
-
return false;
|
861 |
-
}
|
862 |
-
|
863 |
-
return $res;
|
864 |
-
}
|
865 |
-
|
866 |
-
/**
|
867 |
-
* Fetches module translation updates from wordpress.org.
|
868 |
-
*
|
869 |
-
* @author Leo Fajardo (@leorw)
|
870 |
-
* @since 2.1.2
|
871 |
-
*
|
872 |
-
* @param string $module_type
|
873 |
-
* @param string $slug
|
874 |
-
*
|
875 |
-
* @return array|null
|
876 |
-
*/
|
877 |
-
private function fetch_wp_org_module_translation_updates( $module_type, $slug ) {
|
878 |
-
$plugin_data = $this->_fs->get_plugin_data();
|
879 |
-
|
880 |
-
$locales = array_values( get_available_languages() );
|
881 |
-
$locales = apply_filters( "{$module_type}_update_check_locales", $locales );
|
882 |
-
$locales = array_unique( $locales );
|
883 |
-
|
884 |
-
$plugin_basename = $this->_fs->get_plugin_basename();
|
885 |
-
if ( 'themes' === $module_type ) {
|
886 |
-
$plugin_basename = $slug;
|
887 |
-
}
|
888 |
-
|
889 |
-
global $wp_version;
|
890 |
-
|
891 |
-
$request_args = array(
|
892 |
-
'timeout' => 15,
|
893 |
-
'body' => array(
|
894 |
-
"{$module_type}" => json_encode(
|
895 |
-
array(
|
896 |
-
"{$module_type}" => array(
|
897 |
-
$plugin_basename => array(
|
898 |
-
'Name' => trim( str_replace( $this->_fs->get_plugin()->premium_suffix, '', $plugin_data['Name'] ) ),
|
899 |
-
'Author' => $plugin_data['Author'],
|
900 |
-
)
|
901 |
-
)
|
902 |
-
)
|
903 |
-
),
|
904 |
-
'translations' => json_encode( $this->get_installed_translations( $module_type, $slug ) ),
|
905 |
-
'locale' => json_encode( $locales )
|
906 |
-
),
|
907 |
-
'user-agent' => ( 'WordPress/' . $wp_version . '; ' . home_url( '/' ) )
|
908 |
-
);
|
909 |
-
|
910 |
-
$url = "http://api.wordpress.org/{$module_type}/update-check/1.1/";
|
911 |
-
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
|
912 |
-
$url = set_url_scheme( $url, 'https' );
|
913 |
-
}
|
914 |
-
|
915 |
-
$raw_response = Freemius::safe_remote_post(
|
916 |
-
$url,
|
917 |
-
$request_args,
|
918 |
-
WP_FS__TIME_24_HOURS_IN_SEC,
|
919 |
-
WP_FS__TIME_12_HOURS_IN_SEC,
|
920 |
-
false
|
921 |
-
);
|
922 |
-
|
923 |
-
if ( is_wp_error( $raw_response ) ) {
|
924 |
-
return null;
|
925 |
-
}
|
926 |
-
|
927 |
-
$response = json_decode( wp_remote_retrieve_body( $raw_response ), true );
|
928 |
-
|
929 |
-
if ( ! is_array( $response ) ) {
|
930 |
-
return null;
|
931 |
-
}
|
932 |
-
|
933 |
-
if ( ! isset( $response['translations'] ) || empty( $response['translations'] ) ) {
|
934 |
-
return null;
|
935 |
-
}
|
936 |
-
|
937 |
-
return $response['translations'];
|
938 |
-
}
|
939 |
-
|
940 |
-
/**
|
941 |
-
* @author Leo Fajardo (@leorw)
|
942 |
-
* @since 2.1.2
|
943 |
-
*
|
944 |
-
* @param string $module_type
|
945 |
-
* @param string $slug
|
946 |
-
*
|
947 |
-
* @return array
|
948 |
-
*/
|
949 |
-
private function get_installed_translations( $module_type, $slug ) {
|
950 |
-
if ( function_exists( 'wp_get_installed_translations' ) ) {
|
951 |
-
return wp_get_installed_translations( $module_type );
|
952 |
-
}
|
953 |
-
|
954 |
-
$dir = "/{$module_type}";
|
955 |
-
|
956 |
-
if ( ! is_dir( WP_LANG_DIR . $dir ) )
|
957 |
-
return array();
|
958 |
-
|
959 |
-
$files = scandir( WP_LANG_DIR . $dir );
|
960 |
-
if ( ! $files )
|
961 |
-
return array();
|
962 |
-
|
963 |
-
$language_data = array();
|
964 |
-
|
965 |
-
foreach ( $files as $file ) {
|
966 |
-
if ( 0 !== strpos( $file, $slug ) ) {
|
967 |
-
continue;
|
968 |
-
}
|
969 |
-
|
970 |
-
if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "{$dir}/{$file}" ) ) {
|
971 |
-
continue;
|
972 |
-
}
|
973 |
-
|
974 |
-
if ( substr( $file, -3 ) !== '.po' ) {
|
975 |
-
continue;
|
976 |
-
}
|
977 |
-
|
978 |
-
if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
|
979 |
-
continue;
|
980 |
-
}
|
981 |
-
|
982 |
-
if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) {
|
983 |
-
continue;
|
984 |
-
}
|
985 |
-
|
986 |
-
list( , $textdomain, $language ) = $match;
|
987 |
-
|
988 |
-
if ( '' === $textdomain ) {
|
989 |
-
$textdomain = 'default';
|
990 |
-
}
|
991 |
-
|
992 |
-
$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "{$dir}/{$file}" );
|
993 |
-
}
|
994 |
-
|
995 |
-
return $language_data;
|
996 |
-
}
|
997 |
-
|
998 |
-
/**
|
999 |
-
* Updates information on the "View version x.x details" page with custom data.
|
1000 |
-
*
|
1001 |
-
* @author Vova Feldman (@svovaf)
|
1002 |
-
* @since 1.0.4
|
1003 |
-
*
|
1004 |
-
* @uses FS_Api
|
1005 |
-
*
|
1006 |
-
* @param object $data
|
1007 |
-
* @param string $action
|
1008 |
-
* @param mixed $args
|
1009 |
-
*
|
1010 |
-
* @return object
|
1011 |
-
*/
|
1012 |
-
function plugins_api_filter( $data, $action = '', $args = null ) {
|
1013 |
-
$this->_logger->entrance();
|
1014 |
-
|
1015 |
-
if ( ( 'plugin_information' !== $action ) ||
|
1016 |
-
! isset( $args->slug )
|
1017 |
-
) {
|
1018 |
-
return $data;
|
1019 |
-
}
|
1020 |
-
|
1021 |
-
$addon = false;
|
1022 |
-
$is_addon = false;
|
1023 |
-
$addon_version = false;
|
1024 |
-
|
1025 |
-
if ( $this->_fs->get_slug() !== $args->slug ) {
|
1026 |
-
$addon = $this->_fs->get_addon_by_slug( $args->slug );
|
1027 |
-
|
1028 |
-
if ( ! is_object( $addon ) ) {
|
1029 |
-
return $data;
|
1030 |
-
}
|
1031 |
-
|
1032 |
-
if ( $this->_fs->is_addon_activated( $addon->id ) ) {
|
1033 |
-
$addon_version = $this->_fs->get_addon_instance( $addon->id )->get_plugin_version();
|
1034 |
-
} else if ( $this->_fs->is_addon_installed( $addon->id ) ) {
|
1035 |
-
$addon_plugin_data = get_plugin_data(
|
1036 |
-
( WP_PLUGIN_DIR . '/' . $this->_fs->get_addon_basename( $addon->id ) ),
|
1037 |
-
false,
|
1038 |
-
false
|
1039 |
-
);
|
1040 |
-
|
1041 |
-
if ( ! empty( $addon_plugin_data ) ) {
|
1042 |
-
$addon_version = $addon_plugin_data['Version'];
|
1043 |
-
}
|
1044 |
-
}
|
1045 |
-
|
1046 |
-
$is_addon = true;
|
1047 |
-
}
|
1048 |
-
|
1049 |
-
$plugin_in_repo = false;
|
1050 |
-
if ( ! $is_addon ) {
|
1051 |
-
// Try to fetch info from .org repository.
|
1052 |
-
$data = self::_fetch_plugin_info_from_repository( $action, $args );
|
1053 |
-
|
1054 |
-
$plugin_in_repo = ( false !== $data );
|
1055 |
-
}
|
1056 |
-
|
1057 |
-
if ( ! $plugin_in_repo ) {
|
1058 |
-
$data = $args;
|
1059 |
-
|
1060 |
-
// Fetch as much as possible info from local files.
|
1061 |
-
$plugin_local_data = $this->_fs->get_plugin_data();
|
1062 |
-
$data->name = $plugin_local_data['Name'];
|
1063 |
-
$data->author = $plugin_local_data['Author'];
|
1064 |
-
$data->sections = array(
|
1065 |
-
'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.',
|
1066 |
-
);
|
1067 |
-
|
1068 |
-
// @todo Store extra plugin info on Freemius or parse readme.txt markup.
|
1069 |
-
/*$info = $this->_fs->get_api_site_scope()->call('/information.json');
|
1070 |
-
|
1071 |
-
if ( !isset($info->error) ) {
|
1072 |
-
$data = $info;
|
1073 |
-
}*/
|
1074 |
-
}
|
1075 |
-
|
1076 |
-
$plugin_version = $is_addon ?
|
1077 |
-
$addon_version :
|
1078 |
-
$this->_fs->get_plugin_version();
|
1079 |
-
|
1080 |
-
// Get plugin's newest update.
|
1081 |
-
$new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false, $plugin_version );
|
1082 |
-
|
1083 |
-
if ( ! is_object( $new_version ) || empty( $new_version->version ) ) {
|
1084 |
-
$data->version = $plugin_version;
|
1085 |
-
} else {
|
1086 |
-
if ( $is_addon ) {
|
1087 |
-
$data->name = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
|
1088 |
-
$data->slug = $addon->slug;
|
1089 |
-
$data->url = WP_FS__ADDRESS;
|
1090 |
-
$data->package = $new_version->url;
|
1091 |
-
}
|
1092 |
-
|
1093 |
-
if ( ! $plugin_in_repo ) {
|
1094 |
-
$data->last_updated = ! is_null( $new_version->updated ) ? $new_version->updated : $new_version->created;
|
1095 |
-
$data->requires = $new_version->requires_platform_version;
|
1096 |
-
$data->tested = $new_version->tested_up_to_version;
|
1097 |
-
}
|
1098 |
-
|
1099 |
-
$data->version = $new_version->version;
|
1100 |
-
$data->download_link = $new_version->url;
|
1101 |
-
|
1102 |
-
if ( isset( $new_version->readme ) && is_object( $new_version->readme ) ) {
|
1103 |
-
$new_version_readme_data = $new_version->readme;
|
1104 |
-
if ( isset( $new_version_readme_data->sections ) ) {
|
1105 |
-
$new_version_readme_data->sections = (array) $new_version_readme_data->sections;
|
1106 |
-
} else {
|
1107 |
-
$new_version_readme_data->sections = array();
|
1108 |
-
}
|
1109 |
-
|
1110 |
-
if ( isset( $data->sections ) ) {
|
1111 |
-
if ( isset( $data->sections['screenshots'] ) ) {
|
1112 |
-
$new_version_readme_data->sections['screenshots'] = $data->sections['screenshots'];
|
1113 |
-
}
|
1114 |
-
|
1115 |
-
if ( isset( $data->sections['reviews'] ) ) {
|
1116 |
-
$new_version_readme_data->sections['reviews'] = $data->sections['reviews'];
|
1117 |
-
}
|
1118 |
-
}
|
1119 |
-
|
1120 |
-
if ( isset( $new_version_readme_data->banners ) ) {
|
1121 |
-
$new_version_readme_data->banners = (array) $new_version_readme_data->banners;
|
1122 |
-
} else if ( isset( $data->banners ) ) {
|
1123 |
-
$new_version_readme_data->banners = $data->banners;
|
1124 |
-
}
|
1125 |
-
|
1126 |
-
$wp_org_sections = array(
|
1127 |
-
'author',
|
1128 |
-
'author_profile',
|
1129 |
-
'rating',
|
1130 |
-
'ratings',
|
1131 |
-
'num_ratings',
|
1132 |
-
'support_threads',
|
1133 |
-
'support_threads_resolved',
|
1134 |
-
'active_installs',
|
1135 |
-
'added',
|
1136 |
-
'homepage'
|
1137 |
-
);
|
1138 |
-
|
1139 |
-
foreach ( $wp_org_sections as $wp_org_section ) {
|
1140 |
-
if ( isset( $data->{$wp_org_section} ) ) {
|
1141 |
-
$new_version_readme_data->{$wp_org_section} = $data->{$wp_org_section};
|
1142 |
-
}
|
1143 |
-
}
|
1144 |
-
|
1145 |
-
$data = $new_version_readme_data;
|
1146 |
-
}
|
1147 |
-
}
|
1148 |
-
|
1149 |
-
return $data;
|
1150 |
-
}
|
1151 |
-
|
1152 |
-
/**
|
1153 |
-
* @author Vova Feldman (@svovaf)
|
1154 |
-
* @since 1.2.1.7
|
1155 |
-
*
|
1156 |
-
* @param number|bool $addon_id
|
1157 |
-
* @param bool|string $newer_than Since 2.2.1
|
1158 |
-
* @param bool|string $fetch_readme Since 2.2.1
|
1159 |
-
*
|
1160 |
-
* @return object
|
1161 |
-
*/
|
1162 |
-
private function get_latest_download_details( $addon_id = false, $newer_than = false, $fetch_readme = true ) {
|
1163 |
-
return $this->_fs->_fetch_latest_version( $addon_id, true, WP_FS__TIME_24_HOURS_IN_SEC, $newer_than, $fetch_readme );
|
1164 |
-
}
|
1165 |
-
|
1166 |
-
/**
|
1167 |
-
* Checks if a given basename has a matching folder name
|
1168 |
-
* with the current context plugin.
|
1169 |
-
*
|
1170 |
-
* @author Vova Feldman (@svovaf)
|
1171 |
-
* @since 1.2.1.6
|
1172 |
-
*
|
1173 |
-
* @return bool
|
1174 |
-
*/
|
1175 |
-
private function is_correct_folder_name() {
|
1176 |
-
return ( $this->_fs->get_target_folder_name() == trim( dirname( $this->_fs->get_plugin_basename() ), '/\\' ) );
|
1177 |
-
}
|
1178 |
-
|
1179 |
-
/**
|
1180 |
-
* This is a special after upgrade handler for migrating modules
|
1181 |
-
* that didn't use the '-premium' suffix folder structure before
|
1182 |
-
* the migration.
|
1183 |
-
*
|
1184 |
-
* @author Vova Feldman (@svovaf)
|
1185 |
-
* @since 1.2.1.6
|
1186 |
-
*
|
1187 |
-
* @param bool $response Install response.
|
1188 |
-
* @param array $hook_extra Extra arguments passed to hooked filters.
|
1189 |
-
* @param array $result Installation result data.
|
1190 |
-
*
|
1191 |
-
* @return bool
|
1192 |
-
*/
|
1193 |
-
function _maybe_update_folder_name( $response, $hook_extra, $result ) {
|
1194 |
-
$basename = $this->_fs->get_plugin_basename();
|
1195 |
-
|
1196 |
-
if ( true !== $response ||
|
1197 |
-
empty( $hook_extra ) ||
|
1198 |
-
empty( $hook_extra['plugin'] ) ||
|
1199 |
-
$basename !== $hook_extra['plugin']
|
1200 |
-
) {
|
1201 |
-
return $response;
|
1202 |
-
}
|
1203 |
-
|
1204 |
-
$active_plugins_basenames = get_option( 'active_plugins' );
|
1205 |
-
|
1206 |
-
foreach ( $active_plugins_basenames as $key => $active_plugin_basename ) {
|
1207 |
-
if ( $basename === $active_plugin_basename ) {
|
1208 |
-
// Get filename including extension.
|
1209 |
-
$filename = basename( $basename );
|
1210 |
-
|
1211 |
-
$new_basename = plugin_basename(
|
1212 |
-
trailingslashit( $this->_fs->is_premium() ? $this->_fs->get_premium_slug() : $this->_fs->get_slug() ) .
|
1213 |
-
$filename
|
1214 |
-
);
|
1215 |
-
|
1216 |
-
// Verify that the expected correct path exists.
|
1217 |
-
if ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $new_basename ) ) ) {
|
1218 |
-
// Override active plugin name.
|
1219 |
-
$active_plugins_basenames[ $key ] = $new_basename;
|
1220 |
-
update_option( 'active_plugins', $active_plugins_basenames );
|
1221 |
-
}
|
1222 |
-
|
1223 |
-
break;
|
1224 |
-
}
|
1225 |
-
}
|
1226 |
-
|
1227 |
-
return $response;
|
1228 |
-
}
|
1229 |
-
|
1230 |
-
#----------------------------------------------------------------------------------
|
1231 |
-
#region Auto Activation
|
1232 |
-
#----------------------------------------------------------------------------------
|
1233 |
-
|
1234 |
-
/**
|
1235 |
-
* Installs and active a plugin when explicitly requested that from a 3rd party service.
|
1236 |
-
*
|
1237 |
-
* This logic was inspired by the TGMPA GPL licensed library by Thomas Griffin.
|
1238 |
-
*
|
1239 |
-
* @link http://tgmpluginactivation.com/
|
1240 |
-
*
|
1241 |
-
* @author Vova Feldman
|
1242 |
-
* @since 1.2.1.7
|
1243 |
-
*
|
1244 |
-
* @link https://make.wordpress.org/plugins/2017/03/16/clarification-of-guideline-8-executable-code-and-installs/
|
1245 |
-
*
|
1246 |
-
* @uses WP_Filesystem
|
1247 |
-
* @uses WP_Error
|
1248 |
-
* @uses WP_Upgrader
|
1249 |
-
* @uses Plugin_Upgrader
|
1250 |
-
* @uses Plugin_Installer_Skin
|
1251 |
-
* @uses Plugin_Upgrader_Skin
|
1252 |
-
*
|
1253 |
-
* @param number|bool $plugin_id
|
1254 |
-
*
|
1255 |
-
* @return array
|
1256 |
-
*/
|
1257 |
-
function install_and_activate_plugin( $plugin_id = false ) {
|
1258 |
-
if ( ! empty( $plugin_id ) && ! FS_Plugin::is_valid_id( $plugin_id ) ) {
|
1259 |
-
// Invalid plugin ID.
|
1260 |
-
return array(
|
1261 |
-
'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ),
|
1262 |
-
'code' => 'invalid_module_id',
|
1263 |
-
);
|
1264 |
-
}
|
1265 |
-
|
1266 |
-
$is_addon = false;
|
1267 |
-
if ( FS_Plugin::is_valid_id( $plugin_id ) &&
|
1268 |
-
$plugin_id != $this->_fs->get_id()
|
1269 |
-
) {
|
1270 |
-
$addon = $this->_fs->get_addon( $plugin_id );
|
1271 |
-
|
1272 |
-
if ( ! is_object( $addon ) ) {
|
1273 |
-
// Invalid add-on ID.
|
1274 |
-
return array(
|
1275 |
-
'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ),
|
1276 |
-
'code' => 'invalid_module_id',
|
1277 |
-
);
|
1278 |
-
}
|
1279 |
-
|
1280 |
-
$slug = $addon->slug;
|
1281 |
-
$premium_slug = $addon->premium_slug;
|
1282 |
-
$title = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
|
1283 |
-
|
1284 |
-
$is_addon = true;
|
1285 |
-
} else {
|
1286 |
-
$slug = $this->_fs->get_slug();
|
1287 |
-
$premium_slug = $this->_fs->get_premium_slug();
|
1288 |
-
$title = $this->_fs->get_plugin_title() .
|
1289 |
-
( $this->_fs->is_addon() ? ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' ) : '' );
|
1290 |
-
}
|
1291 |
-
|
1292 |
-
if ( $this->is_premium_plugin_active( $plugin_id ) ) {
|
1293 |
-
// Premium version already activated.
|
1294 |
-
return array(
|
1295 |
-
'message' => $is_addon ?
|
1296 |
-
$this->_fs->get_text_inline( 'Premium add-on version already installed.', 'auto-install-error-premium-addon-activated' ) :
|
1297 |
-
$this->_fs->get_text_inline( 'Premium version already active.', 'auto-install-error-premium-activated' ),
|
1298 |
-
'code' => 'premium_installed',
|
1299 |
-
);
|
1300 |
-
}
|
1301 |
-
|
1302 |
-
$latest_version = $this->get_latest_download_details( $plugin_id, false, false );
|
1303 |
-
$target_folder = $premium_slug;
|
1304 |
-
|
1305 |
-
// Prep variables for Plugin_Installer_Skin class.
|
1306 |
-
$extra = array();
|
1307 |
-
$extra['slug'] = $target_folder;
|
1308 |
-
$source = $latest_version->url;
|
1309 |
-
$api = null;
|
1310 |
-
|
1311 |
-
$install_url = add_query_arg(
|
1312 |
-
array(
|
1313 |
-
'action' => 'install-plugin',
|
1314 |
-
'plugin' => urlencode( $slug ),
|
1315 |
-
),
|
1316 |
-
'update.php'
|
1317 |
-
);
|
1318 |
-
|
1319 |
-
if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
|
1320 |
-
// Include required resources for the installation.
|
1321 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
1322 |
-
}
|
1323 |
-
|
1324 |
-
$skin_args = array(
|
1325 |
-
'type' => 'web',
|
1326 |
-
'title' => sprintf( $this->_fs->get_text_inline( 'Installing plugin: %s', 'installing-plugin-x' ), $title ),
|
1327 |
-
'url' => esc_url_raw( $install_url ),
|
1328 |
-
'nonce' => 'install-plugin_' . $slug,
|
1329 |
-
'plugin' => '',
|
1330 |
-
'api' => $api,
|
1331 |
-
'extra' => $extra,
|
1332 |
-
);
|
1333 |
-
|
1334 |
-
// $skin = new Automatic_Upgrader_Skin( $skin_args );
|
1335 |
-
// $skin = new Plugin_Installer_Skin( $skin_args );
|
1336 |
-
$skin = new WP_Ajax_Upgrader_Skin( $skin_args );
|
1337 |
-
|
1338 |
-
// Create a new instance of Plugin_Upgrader.
|
1339 |
-
$upgrader = new Plugin_Upgrader( $skin );
|
1340 |
-
|
1341 |
-
// Perform the action and install the plugin from the $source urldecode().
|
1342 |
-
add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 );
|
1343 |
-
|
1344 |
-
$install_result = $upgrader->install( $source );
|
1345 |
-
|
1346 |
-
remove_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1 );
|
1347 |
-
|
1348 |
-
if ( is_wp_error( $install_result ) ) {
|
1349 |
-
return array(
|
1350 |
-
'message' => $install_result->get_error_message(),
|
1351 |
-
'code' => $install_result->get_error_code(),
|
1352 |
-
);
|
1353 |
-
} elseif ( is_wp_error( $skin->result ) ) {
|
1354 |
-
return array(
|
1355 |
-
'message' => $skin->result->get_error_message(),
|
1356 |
-
'code' => $skin->result->get_error_code(),
|
1357 |
-
);
|
1358 |
-
} elseif ( $skin->get_errors()->get_error_code() ) {
|
1359 |
-
return array(
|
1360 |
-
'message' => $skin->get_error_messages(),
|
1361 |
-
'code' => 'unknown',
|
1362 |
-
);
|
1363 |
-
} elseif ( is_null( $install_result ) ) {
|
1364 |
-
global $wp_filesystem;
|
1365 |
-
|
1366 |
-
$error_code = 'unable_to_connect_to_filesystem';
|
1367 |
-
$error_message = $this->_fs->get_text_inline( 'Unable to connect to the filesystem. Please confirm your credentials.' );
|
1368 |
-
|
1369 |
-
// Pass through the error from WP_Filesystem if one was raised.
|
1370 |
-
if ( $wp_filesystem instanceof WP_Filesystem_Base &&
|
1371 |
-
is_wp_error( $wp_filesystem->errors ) &&
|
1372 |
-
$wp_filesystem->errors->get_error_code()
|
1373 |
-
) {
|
1374 |
-
$error_message = $wp_filesystem->errors->get_error_message();
|
1375 |
-
}
|
1376 |
-
|
1377 |
-
return array(
|
1378 |
-
'message' => $error_message,
|
1379 |
-
'code' => $error_code,
|
1380 |
-
);
|
1381 |
-
}
|
1382 |
-
|
1383 |
-
// Grab the full path to the main plugin's file.
|
1384 |
-
$plugin_activate = $upgrader->plugin_info();
|
1385 |
-
|
1386 |
-
// Try to activate the plugin.
|
1387 |
-
$activation_result = $this->try_activate_plugin( $plugin_activate );
|
1388 |
-
|
1389 |
-
if ( is_wp_error( $activation_result ) ) {
|
1390 |
-
return array(
|
1391 |
-
'message' => $activation_result->get_error_message(),
|
1392 |
-
'code' => $activation_result->get_error_code(),
|
1393 |
-
);
|
1394 |
-
}
|
1395 |
-
|
1396 |
-
return $skin->get_upgrade_messages();
|
1397 |
-
}
|
1398 |
-
|
1399 |
-
/**
|
1400 |
-
* Tries to activate a plugin. If fails, returns the error.
|
1401 |
-
*
|
1402 |
-
* @author Vova Feldman
|
1403 |
-
* @since 1.2.1.7
|
1404 |
-
*
|
1405 |
-
* @param string $file_path Path within wp-plugins/ to main plugin file.
|
1406 |
-
* This determines the styling of the output messages.
|
1407 |
-
*
|
1408 |
-
* @return bool|WP_Error
|
1409 |
-
*/
|
1410 |
-
protected function try_activate_plugin( $file_path ) {
|
1411 |
-
$activate = activate_plugin( $file_path, '', $this->_fs->is_network_active() );
|
1412 |
-
|
1413 |
-
return is_wp_error( $activate ) ?
|
1414 |
-
$activate :
|
1415 |
-
true;
|
1416 |
-
}
|
1417 |
-
|
1418 |
-
/**
|
1419 |
-
* Check if a premium module version is already active.
|
1420 |
-
*
|
1421 |
-
* @author Vova Feldman
|
1422 |
-
* @since 1.2.1.7
|
1423 |
-
*
|
1424 |
-
* @param number|bool $plugin_id
|
1425 |
-
*
|
1426 |
-
* @return bool
|
1427 |
-
*/
|
1428 |
-
private function is_premium_plugin_active( $plugin_id = false ) {
|
1429 |
-
if ( $plugin_id != $this->_fs->get_id() ) {
|
1430 |
-
return $this->_fs->is_addon_activated( $plugin_id, true );
|
1431 |
-
}
|
1432 |
-
|
1433 |
-
return is_plugin_active( $this->_fs->premium_plugin_basename() );
|
1434 |
-
}
|
1435 |
-
|
1436 |
-
/**
|
1437 |
-
* Store the basename since it's not always available in the `_maybe_adjust_source_dir` method below.
|
1438 |
-
*
|
1439 |
-
* @author Leo Fajardo (@leorw)
|
1440 |
-
* @since 2.2.1
|
1441 |
-
*
|
1442 |
-
* @param bool|WP_Error $response Response.
|
1443 |
-
* @param array $hook_extra Extra arguments passed to hooked filters.
|
1444 |
-
*
|
1445 |
-
* @return bool|WP_Error
|
1446 |
-
*/
|
1447 |
-
static function _store_basename_for_source_adjustment( $response, $hook_extra ) {
|
1448 |
-
if ( isset( $hook_extra['plugin'] ) ) {
|
1449 |
-
self::$_upgrade_basename = $hook_extra['plugin'];
|
1450 |
-
} else if ( isset( $hook_extra['theme'] ) ) {
|
1451 |
-
self::$_upgrade_basename = $hook_extra['theme'];
|
1452 |
-
} else {
|
1453 |
-
self::$_upgrade_basename = null;
|
1454 |
-
}
|
1455 |
-
|
1456 |
-
return $response;
|
1457 |
-
}
|
1458 |
-
|
1459 |
-
/**
|
1460 |
-
* Adjust the plugin directory name if necessary.
|
1461 |
-
* Assumes plugin has a folder (not a single file plugin).
|
1462 |
-
*
|
1463 |
-
* The final destination directory of a plugin is based on the subdirectory name found in the
|
1464 |
-
* (un)zipped source. In some cases this subdirectory name is not the same as the expected
|
1465 |
-
* slug and the plugin will not be recognized as installed. This is fixed by adjusting
|
1466 |
-
* the temporary unzipped source subdirectory name to the expected plugin slug.
|
1467 |
-
*
|
1468 |
-
* @author Vova Feldman
|
1469 |
-
* @since 1.2.1.7
|
1470 |
-
* @since 2.2.1 The method was converted to static since when the admin update bulk products via the Updates section, the logic applies the `upgrader_source_selection` filter for every product that is being updated.
|
1471 |
-
*
|
1472 |
-
* @param string $source Path to upgrade/zip-file-name.tmp/subdirectory/.
|
1473 |
-
* @param string $remote_source Path to upgrade/zip-file-name.tmp.
|
1474 |
-
* @param \WP_Upgrader $upgrader Instance of the upgrader which installs the plugin.
|
1475 |
-
*
|
1476 |
-
* @return string|WP_Error
|
1477 |
-
*/
|
1478 |
-
static function _maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
|
1479 |
-
if ( ! is_object( $GLOBALS['wp_filesystem'] ) ) {
|
1480 |
-
return $source;
|
1481 |
-
}
|
1482 |
-
|
1483 |
-
$basename = self::$_upgrade_basename;
|
1484 |
-
$is_theme = false;
|
1485 |
-
|
1486 |
-
// Figure out what the slug is supposed to be.
|
1487 |
-
if ( isset( $upgrader->skin->options['extra'] ) ) {
|
1488 |
-
// Set by the auto-install logic.
|
1489 |
-
$desired_slug = $upgrader->skin->options['extra']['slug'];
|
1490 |
-
} else if ( ! empty( $basename ) ) {
|
1491 |
-
/**
|
1492 |
-
* If it doesn't end with ".php", it's a theme.
|
1493 |
-
*
|
1494 |
-
* @author Leo Fajardo (@leorw)
|
1495 |
-
* @since 2.2.1
|
1496 |
-
*/
|
1497 |
-
$is_theme = ( ! fs_ends_with( $basename, '.php' ) );
|
1498 |
-
|
1499 |
-
$desired_slug = ( ! $is_theme ) ?
|
1500 |
-
dirname( $basename ) :
|
1501 |
-
// Theme slug
|
1502 |
-
$basename;
|
1503 |
-
} else {
|
1504 |
-
// Can't figure out the desired slug, stop the execution.
|
1505 |
-
return $source;
|
1506 |
-
}
|
1507 |
-
|
1508 |
-
if ( is_multisite() ) {
|
1509 |
-
/**
|
1510 |
-
* If we are running in a multisite environment and the product is not network activated,
|
1511 |
-
* the instance will not exist anyway. Therefore, try to update the source if necessary
|
1512 |
-
* regardless if the Freemius instance of the product exists or not.
|
1513 |
-
*
|
1514 |
-
* @author Vova Feldman
|
1515 |
-
*/
|
1516 |
-
} else if ( ! empty( $basename ) ) {
|
1517 |
-
$fs = Freemius::get_instance_by_file(
|
1518 |
-
$basename,
|
1519 |
-
$is_theme ?
|
1520 |
-
WP_FS__MODULE_TYPE_THEME :
|
1521 |
-
WP_FS__MODULE_TYPE_PLUGIN
|
1522 |
-
);
|
1523 |
-
|
1524 |
-
if ( ! is_object( $fs ) ) {
|
1525 |
-
/**
|
1526 |
-
* If the Freemius instance does not exist on a non-multisite network environment, it means that:
|
1527 |
-
* 1. The product is not powered by Freemius; OR
|
1528 |
-
* 2. The product is not activated, therefore, we don't mind if after the update the folder name will change.
|
1529 |
-
*
|
1530 |
-
* @author Leo Fajardo (@leorw)
|
1531 |
-
* @since 2.2.1
|
1532 |
-
*/
|
1533 |
-
return $source;
|
1534 |
-
}
|
1535 |
-
}
|
1536 |
-
|
1537 |
-
$subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) );
|
1538 |
-
|
1539 |
-
if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) {
|
1540 |
-
$from_path = untrailingslashit( $source );
|
1541 |
-
$to_path = trailingslashit( $remote_source ) . $desired_slug;
|
1542 |
-
|
1543 |
-
if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) {
|
1544 |
-
return trailingslashit( $to_path );
|
1545 |
-
}
|
1546 |
-
|
1547 |
-
return new WP_Error(
|
1548 |
-
'rename_failed',
|
1549 |
-
fs_text_inline( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'module-package-rename-failure' ),
|
1550 |
-
array(
|
1551 |
-
'found' => $subdir_name,
|
1552 |
-
'expected' => $desired_slug
|
1553 |
-
)
|
1554 |
-
);
|
1555 |
-
}
|
1556 |
-
|
1557 |
-
return $source;
|
1558 |
-
}
|
1559 |
-
|
1560 |
-
#endregion
|
1561 |
-
}
|
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 1.0.4
|
7 |
+
*
|
8 |
+
* @link https://github.com/easydigitaldownloads/EDD-License-handler/blob/master/EDD_SL_Plugin_Updater.php
|
9 |
+
*/
|
10 |
+
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
class FS_Plugin_Updater {
|
16 |
+
|
17 |
+
/**
|
18 |
+
* @var Freemius
|
19 |
+
* @since 1.0.4
|
20 |
+
*/
|
21 |
+
private $_fs;
|
22 |
+
/**
|
23 |
+
* @var FS_Logger
|
24 |
+
* @since 1.0.4
|
25 |
+
*/
|
26 |
+
private $_logger;
|
27 |
+
/**
|
28 |
+
* @var object
|
29 |
+
* @since 1.1.8.1
|
30 |
+
*/
|
31 |
+
private $_update_details;
|
32 |
+
/**
|
33 |
+
* @var array
|
34 |
+
* @since 2.1.2
|
35 |
+
*/
|
36 |
+
private $_translation_updates;
|
37 |
+
|
38 |
+
private static $_upgrade_basename = null;
|
39 |
+
|
40 |
+
#--------------------------------------------------------------------------------
|
41 |
+
#region Singleton
|
42 |
+
#--------------------------------------------------------------------------------
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @var FS_Plugin_Updater[]
|
46 |
+
* @since 2.0.0
|
47 |
+
*/
|
48 |
+
private static $_INSTANCES = array();
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @param Freemius $freemius
|
52 |
+
*
|
53 |
+
* @return FS_Plugin_Updater
|
54 |
+
*/
|
55 |
+
static function instance( Freemius $freemius ) {
|
56 |
+
$key = $freemius->get_id();
|
57 |
+
|
58 |
+
if ( ! isset( self::$_INSTANCES[ $key ] ) ) {
|
59 |
+
self::$_INSTANCES[ $key ] = new self( $freemius );
|
60 |
+
}
|
61 |
+
|
62 |
+
return self::$_INSTANCES[ $key ];
|
63 |
+
}
|
64 |
+
|
65 |
+
#endregion
|
66 |
+
|
67 |
+
private function __construct( Freemius $freemius ) {
|
68 |
+
$this->_fs = $freemius;
|
69 |
+
|
70 |
+
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $freemius->get_slug() . '_updater', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
71 |
+
|
72 |
+
$this->filters();
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Initiate required filters.
|
77 |
+
*
|
78 |
+
* @author Vova Feldman (@svovaf)
|
79 |
+
* @since 1.0.4
|
80 |
+
*/
|
81 |
+
private function filters() {
|
82 |
+
// Override request for plugin information
|
83 |
+
add_filter( 'plugins_api', array( &$this, 'plugins_api_filter' ), 10, 3 );
|
84 |
+
|
85 |
+
$this->add_transient_filters();
|
86 |
+
|
87 |
+
/**
|
88 |
+
* If user has the premium plugin's code but do NOT have an active license,
|
89 |
+
* encourage him to upgrade by showing that there's a new release, but instead
|
90 |
+
* of showing an update link, show upgrade link to the pricing page.
|
91 |
+
*
|
92 |
+
* @since 1.1.6
|
93 |
+
*
|
94 |
+
*/
|
95 |
+
// WP 2.9+
|
96 |
+
add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
|
97 |
+
&$this,
|
98 |
+
'catch_plugin_update_row'
|
99 |
+
), 9 );
|
100 |
+
add_action( "after_plugin_row_{$this->_fs->get_plugin_basename()}", array(
|
101 |
+
&$this,
|
102 |
+
'edit_and_echo_plugin_update_row'
|
103 |
+
), 11, 2 );
|
104 |
+
|
105 |
+
if ( ! $this->_fs->has_any_active_valid_license() ) {
|
106 |
+
add_action( 'admin_head', array( &$this, 'catch_plugin_information_dialog_contents' ) );
|
107 |
+
}
|
108 |
+
|
109 |
+
if ( ! WP_FS__IS_PRODUCTION_MODE ) {
|
110 |
+
add_filter( 'http_request_host_is_external', array(
|
111 |
+
$this,
|
112 |
+
'http_request_host_is_external_filter'
|
113 |
+
), 10, 3 );
|
114 |
+
}
|
115 |
+
|
116 |
+
if ( $this->_fs->is_premium() ) {
|
117 |
+
if ( ! $this->is_correct_folder_name() ) {
|
118 |
+
add_filter( 'upgrader_post_install', array( &$this, '_maybe_update_folder_name' ), 10, 3 );
|
119 |
+
}
|
120 |
+
|
121 |
+
add_filter( 'upgrader_pre_install', array( 'FS_Plugin_Updater', '_store_basename_for_source_adjustment' ), 1, 2 );
|
122 |
+
add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 );
|
123 |
+
|
124 |
+
if ( ! $this->_fs->has_any_active_valid_license() ) {
|
125 |
+
add_filter( 'wp_prepare_themes_for_js', array( &$this, 'change_theme_update_info_html' ), 10, 1 );
|
126 |
+
}
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* @author Leo Fajardo (@leorw)
|
132 |
+
* @since 2.1.4
|
133 |
+
*/
|
134 |
+
function catch_plugin_information_dialog_contents() {
|
135 |
+
if (
|
136 |
+
'plugin-information' !== fs_request_get( 'tab', false ) ||
|
137 |
+
$this->_fs->get_slug() !== fs_request_get( 'plugin', false )
|
138 |
+
) {
|
139 |
+
return;
|
140 |
+
}
|
141 |
+
|
142 |
+
add_action( 'admin_footer', array( &$this, 'edit_and_echo_plugin_information_dialog_contents' ), 0, 1 );
|
143 |
+
|
144 |
+
ob_start();
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* @author Leo Fajardo (@leorw)
|
149 |
+
* @since 2.1.4
|
150 |
+
*
|
151 |
+
* @param string $hook_suffix
|
152 |
+
*/
|
153 |
+
function edit_and_echo_plugin_information_dialog_contents( $hook_suffix ) {
|
154 |
+
if (
|
155 |
+
'plugin-information' !== fs_request_get( 'tab', false ) ||
|
156 |
+
$this->_fs->get_slug() !== fs_request_get( 'plugin', false )
|
157 |
+
) {
|
158 |
+
return;
|
159 |
+
}
|
160 |
+
|
161 |
+
$license = $this->_fs->_get_license();
|
162 |
+
|
163 |
+
$subscription = ( is_object( $license ) && ! $license->is_lifetime() ) ?
|
164 |
+
$this->_fs->_get_subscription( $license->id ) :
|
165 |
+
null;
|
166 |
+
|
167 |
+
$contents = ob_get_clean();
|
168 |
+
|
169 |
+
$update_button_id_attribute_pos = strpos( $contents, 'id="plugin_update_from_iframe"' );
|
170 |
+
|
171 |
+
if ( false !== $update_button_id_attribute_pos ) {
|
172 |
+
$update_button_start_pos = strrpos(
|
173 |
+
substr( $contents, 0, $update_button_id_attribute_pos ),
|
174 |
+
'<a'
|
175 |
+
);
|
176 |
+
|
177 |
+
$update_button_end_pos = ( strpos( $contents, '</a>', $update_button_id_attribute_pos ) + strlen( '</a>' ) );
|
178 |
+
|
179 |
+
/**
|
180 |
+
* The part of the contents without the update button.
|
181 |
+
*
|
182 |
+
* @author Leo Fajardo (@leorw)
|
183 |
+
* @since 2.2.5
|
184 |
+
*/
|
185 |
+
$modified_contents = substr( $contents, 0, $update_button_start_pos );
|
186 |
+
|
187 |
+
$update_button = substr( $contents, $update_button_start_pos, ( $update_button_end_pos - $update_button_start_pos ) );
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Replace the plugin information dialog's "Install Update Now" button's text and URL. If there's a license,
|
191 |
+
* the text will be "Renew license" and will link to the checkout page with the license's billing cycle
|
192 |
+
* and quota. If there's no license, the text will be "Buy license" and will link to the pricing page.
|
193 |
+
*/
|
194 |
+
$update_button = preg_replace(
|
195 |
+
'/(\<a.+)(id="plugin_update_from_iframe")(.+href=")([^\s]+)(".*\>)(.+)(\<\/a>)/is',
|
196 |
+
is_object( $license ) ?
|
197 |
+
sprintf(
|
198 |
+
'$1$3%s$5%s$7',
|
199 |
+
$this->_fs->checkout_url(
|
200 |
+
is_object( $subscription ) ?
|
201 |
+
( 1 == $subscription->billing_cycle ? WP_FS__PERIOD_MONTHLY : WP_FS__PERIOD_ANNUALLY ) :
|
202 |
+
WP_FS__PERIOD_LIFETIME,
|
203 |
+
false,
|
204 |
+
array( 'licenses' => $license->quota )
|
205 |
+
),
|
206 |
+
fs_text_inline( 'Renew license', 'renew-license', $this->_fs->get_slug() )
|
207 |
+
) :
|
208 |
+
sprintf(
|
209 |
+
'$1$3%s$5%s$7',
|
210 |
+
$this->_fs->pricing_url(),
|
211 |
+
fs_text_inline( 'Buy license', 'buy-license', $this->_fs->get_slug() )
|
212 |
+
),
|
213 |
+
$update_button
|
214 |
+
);
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Append the modified button.
|
218 |
+
*
|
219 |
+
* @author Leo Fajardo (@leorw)
|
220 |
+
* @since 2.2.5
|
221 |
+
*/
|
222 |
+
$modified_contents .= $update_button;
|
223 |
+
|
224 |
+
/**
|
225 |
+
* Append the remaining part of the contents after the update button.
|
226 |
+
*
|
227 |
+
* @author Leo Fajardo (@leorw)
|
228 |
+
* @since 2.2.5
|
229 |
+
*/
|
230 |
+
$modified_contents .= substr( $contents, $update_button_end_pos );
|
231 |
+
|
232 |
+
$contents = $modified_contents;
|
233 |
+
}
|
234 |
+
|
235 |
+
echo $contents;
|
236 |
+
}
|
237 |
+
|
238 |
+
/**
|
239 |
+
* @author Vova Feldman (@svovaf)
|
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;
|
247 |
+
}
|
248 |
+
|
249 |
+
add_filter( 'pre_set_site_transient_update_plugins', array(
|
250 |
+
&$this,
|
251 |
+
'pre_set_site_transient_update_plugins_filter'
|
252 |
+
) );
|
253 |
+
|
254 |
+
add_filter( 'pre_set_site_transient_update_themes', array(
|
255 |
+
&$this,
|
256 |
+
'pre_set_site_transient_update_plugins_filter'
|
257 |
+
) );
|
258 |
+
}
|
259 |
+
|
260 |
+
/**
|
261 |
+
* @author Vova Feldman (@svovaf)
|
262 |
+
* @since 2.0.0
|
263 |
+
*/
|
264 |
+
private function remove_transient_filters() {
|
265 |
+
remove_filter( 'pre_set_site_transient_update_plugins', array(
|
266 |
+
&$this,
|
267 |
+
'pre_set_site_transient_update_plugins_filter'
|
268 |
+
) );
|
269 |
+
|
270 |
+
remove_filter( 'pre_set_site_transient_update_themes', array(
|
271 |
+
&$this,
|
272 |
+
'pre_set_site_transient_update_plugins_filter'
|
273 |
+
) );
|
274 |
+
}
|
275 |
+
|
276 |
+
/**
|
277 |
+
* Capture plugin update row by turning output buffering.
|
278 |
+
*
|
279 |
+
* @author Vova Feldman (@svovaf)
|
280 |
+
* @since 1.1.6
|
281 |
+
*/
|
282 |
+
function catch_plugin_update_row() {
|
283 |
+
ob_start();
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* Overrides default update message format with "renew your license" message.
|
288 |
+
*
|
289 |
+
* @author Vova Feldman (@svovaf)
|
290 |
+
* @since 1.1.6
|
291 |
+
*
|
292 |
+
* @param string $file
|
293 |
+
* @param array $plugin_data
|
294 |
+
*/
|
295 |
+
function edit_and_echo_plugin_update_row( $file, $plugin_data ) {
|
296 |
+
$plugin_update_row = ob_get_clean();
|
297 |
+
|
298 |
+
$current = get_site_transient( 'update_plugins' );
|
299 |
+
if ( ! isset( $current->response[ $file ] ) ) {
|
300 |
+
echo $plugin_update_row;
|
301 |
+
|
302 |
+
return;
|
303 |
+
}
|
304 |
+
|
305 |
+
$r = $current->response[ $file ];
|
306 |
+
|
307 |
+
$has_beta_update = $this->_fs->has_beta_update();
|
308 |
+
|
309 |
+
if ( $this->_fs->has_any_active_valid_license() ) {
|
310 |
+
if ( $has_beta_update ) {
|
311 |
+
/**
|
312 |
+
* Turn the "new version" text into "new Beta version".
|
313 |
+
*
|
314 |
+
* Sample input:
|
315 |
+
* There is a new version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
|
316 |
+
* Output:
|
317 |
+
* There is a new Beta version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
|
318 |
+
*
|
319 |
+
* @author Leo Fajardo (@leorw)
|
320 |
+
* @since 2.3.0
|
321 |
+
*/
|
322 |
+
$plugin_update_row = preg_replace(
|
323 |
+
'/(\<div.+>)(.+)(\<a.+href="([^\s]+)"([^\<]+)\>.+\<a.+)(\<\/div\>)/is',
|
324 |
+
(
|
325 |
+
'$1' .
|
326 |
+
sprintf(
|
327 |
+
fs_text_inline( 'There is a %s of %s available.', 'new-version-available', $this->_fs->get_slug() ),
|
328 |
+
$has_beta_update ?
|
329 |
+
fs_text_inline( 'new Beta version', 'new-beta-version', $this->_fs->get_slug() ) :
|
330 |
+
fs_text_inline( 'new version', 'new-version', $this->_fs->get_slug() ),
|
331 |
+
$this->_fs->get_plugin_title()
|
332 |
+
) .
|
333 |
+
' ' .
|
334 |
+
'$3' .
|
335 |
+
'$6'
|
336 |
+
),
|
337 |
+
$plugin_update_row
|
338 |
+
);
|
339 |
+
}
|
340 |
+
} else {
|
341 |
+
/**
|
342 |
+
* Turn the "new version" text into a link that opens the plugin information dialog when clicked and
|
343 |
+
* make the "View version x details" text link to the checkout page instead of opening the plugin
|
344 |
+
* information dialog when clicked.
|
345 |
+
*
|
346 |
+
* Sample input:
|
347 |
+
* There is a new version of Awesome Plugin available. <a href="...>View version x.y.z details</a> or <a href="...>update now</a>.
|
348 |
+
* Output:
|
349 |
+
* There is a <a href="...>new version</a> of Awesome Plugin available. <a href="...>Buy a license now</a> to access version x.y.z security & feature updates, and support.
|
350 |
+
* OR
|
351 |
+
* There is a <a href="...>new Beta version</a> of Awesome Plugin available. <a href="...>Buy a license now</a> to access version x.y.z security & feature updates, and support.
|
352 |
+
*
|
353 |
+
* @author Leo Fajardo (@leorw)
|
354 |
+
*/
|
355 |
+
$plugin_update_row = preg_replace(
|
356 |
+
'/(\<div.+>)(.+)(\<a.+href="([^\s]+)"([^\<]+)\>.+\<a.+)(\<\/div\>)/is',
|
357 |
+
(
|
358 |
+
'$1' .
|
359 |
+
sprintf(
|
360 |
+
fs_text_inline( 'There is a %s of %s available.', 'new-version-available', $this->_fs->get_slug() ),
|
361 |
+
sprintf(
|
362 |
+
'<a href="$4"%s>%s</a>',
|
363 |
+
'$5',
|
364 |
+
$has_beta_update ?
|
365 |
+
fs_text_inline( 'new Beta version', 'new-beta-version', $this->_fs->get_slug() ) :
|
366 |
+
fs_text_inline( 'new version', 'new-version', $this->_fs->get_slug() )
|
367 |
+
),
|
368 |
+
$this->_fs->get_plugin_title()
|
369 |
+
) .
|
370 |
+
' ' .
|
371 |
+
$this->_fs->version_upgrade_checkout_link( $r->new_version ) .
|
372 |
+
'$6'
|
373 |
+
),
|
374 |
+
$plugin_update_row
|
375 |
+
);
|
376 |
+
}
|
377 |
+
|
378 |
+
if (
|
379 |
+
$this->_fs->is_plugin() &&
|
380 |
+
isset( $r->upgrade_notice ) &&
|
381 |
+
strlen( trim( $r->upgrade_notice ) ) > 0
|
382 |
+
) {
|
383 |
+
$slug = $this->_fs->get_slug();
|
384 |
+
|
385 |
+
$upgrade_notice_html = sprintf(
|
386 |
+
'<p class="notice fs-upgrade-notice fs-slug-%1$s fs-type-%2$s" data-slug="%1$s" data-type="%2$s"><strong>%3$s</strong> %4$s</p>',
|
387 |
+
$slug,
|
388 |
+
$this->_fs->get_module_type(),
|
389 |
+
fs_text_inline( 'Important Upgrade Notice:', 'upgrade_notice', $slug ),
|
390 |
+
esc_html( $r->upgrade_notice )
|
391 |
+
);
|
392 |
+
|
393 |
+
$plugin_update_row = str_replace( '</div>', '</div>' . $upgrade_notice_html, $plugin_update_row );
|
394 |
+
}
|
395 |
+
|
396 |
+
echo $plugin_update_row;
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* @author Leo Fajardo (@leorw)
|
401 |
+
* @since 2.0.2
|
402 |
+
*
|
403 |
+
* @param array $prepared_themes
|
404 |
+
*
|
405 |
+
* @return array
|
406 |
+
*/
|
407 |
+
function change_theme_update_info_html( $prepared_themes ) {
|
408 |
+
$theme_basename = $this->_fs->get_plugin_basename();
|
409 |
+
|
410 |
+
if ( ! isset( $prepared_themes[ $theme_basename ] ) ) {
|
411 |
+
return $prepared_themes;
|
412 |
+
}
|
413 |
+
|
414 |
+
$themes_update = get_site_transient( 'update_themes' );
|
415 |
+
if ( ! isset( $themes_update->response[ $theme_basename ] ) ||
|
416 |
+
empty( $themes_update->response[ $theme_basename ]['package'] )
|
417 |
+
) {
|
418 |
+
return $prepared_themes;
|
419 |
+
}
|
420 |
+
|
421 |
+
$prepared_themes[ $theme_basename ]['update'] = preg_replace(
|
422 |
+
'/(\<p.+>)(.+)(\<a.+\<a.+)\.(.+\<\/p\>)/is',
|
423 |
+
'$1 $2 ' . $this->_fs->version_upgrade_checkout_link( $themes_update->response[ $theme_basename ]['new_version'] ) .
|
424 |
+
'$4',
|
425 |
+
$prepared_themes[ $theme_basename ]['update']
|
426 |
+
);
|
427 |
+
|
428 |
+
// Set to false to prevent the "Update now" link for the context theme from being shown on the "Themes" page.
|
429 |
+
$prepared_themes[ $theme_basename ]['hasPackage'] = false;
|
430 |
+
|
431 |
+
return $prepared_themes;
|
432 |
+
}
|
433 |
+
|
434 |
+
/**
|
435 |
+
* Since WP version 3.6, a new security feature was added that denies access to repository with a local ip.
|
436 |
+
* During development mode we want to be able updating plugin versions via our localhost repository. This
|
437 |
+
* filter white-list all domains including "api.freemius".
|
438 |
+
*
|
439 |
+
* @link http://www.emanueletessore.com/wordpress-download-failed-valid-url-provided/
|
440 |
+
*
|
441 |
+
* @author Vova Feldman (@svovaf)
|
442 |
+
* @since 1.0.4
|
443 |
+
*
|
444 |
+
* @param bool $allow
|
445 |
+
* @param string $host
|
446 |
+
* @param string $url
|
447 |
+
*
|
448 |
+
* @return bool
|
449 |
+
*/
|
450 |
+
function http_request_host_is_external_filter( $allow, $host, $url ) {
|
451 |
+
return ( false !== strpos( $host, 'freemius' ) ) ? true : $allow;
|
452 |
+
}
|
453 |
+
|
454 |
+
/**
|
455 |
+
* Check for Updates at the defined API endpoint and modify the update array.
|
456 |
+
*
|
457 |
+
* This function dives into the update api just when WordPress creates its update array,
|
458 |
+
* then adds a custom API call and injects the custom plugin data retrieved from the API.
|
459 |
+
* It is reassembled from parts of the native WordPress plugin update code.
|
460 |
+
* See wp-includes/update.php line 121 for the original wp_update_plugins() function.
|
461 |
+
*
|
462 |
+
* @author Vova Feldman (@svovaf)
|
463 |
+
* @since 1.0.4
|
464 |
+
*
|
465 |
+
* @uses FS_Api
|
466 |
+
*
|
467 |
+
* @param object $transient_data Update array build by WordPress.
|
468 |
+
*
|
469 |
+
* @return object Modified update array with custom plugin data.
|
470 |
+
*/
|
471 |
+
function pre_set_site_transient_update_plugins_filter( $transient_data ) {
|
472 |
+
$this->_logger->entrance();
|
473 |
+
|
474 |
+
/**
|
475 |
+
* "plugins" or "themes".
|
476 |
+
*
|
477 |
+
* @author Leo Fajardo (@leorw)
|
478 |
+
* @since 1.2.2
|
479 |
+
*/
|
480 |
+
$module_type = $this->_fs->get_module_type() . 's';
|
481 |
+
|
482 |
+
/**
|
483 |
+
* Ensure that we don't mix plugins update info with themes update info.
|
484 |
+
*
|
485 |
+
* @author Leo Fajardo (@leorw)
|
486 |
+
* @since 1.2.2
|
487 |
+
*/
|
488 |
+
if ( "pre_set_site_transient_update_{$module_type}" !== current_filter() ) {
|
489 |
+
return $transient_data;
|
490 |
+
}
|
491 |
+
|
492 |
+
if ( empty( $transient_data ) ||
|
493 |
+
defined( 'WP_FS__UNINSTALL_MODE' )
|
494 |
+
) {
|
495 |
+
return $transient_data;
|
496 |
+
}
|
497 |
+
|
498 |
+
global $wp_current_filter;
|
499 |
+
|
500 |
+
$current_plugin_version = $this->_fs->get_plugin_version();
|
501 |
+
|
502 |
+
if ( ! empty( $wp_current_filter ) && 'upgrader_process_complete' === $wp_current_filter[0] ) {
|
503 |
+
if (
|
504 |
+
is_null( $this->_update_details ) ||
|
505 |
+
( is_object( $this->_update_details ) && $this->_update_details->new_version !== $current_plugin_version )
|
506 |
+
) {
|
507 |
+
/**
|
508 |
+
* After an update, clear the stored update details and reparse the plugin's main file in order to get
|
509 |
+
* the updated version's information and prevent the previous update information from showing up on the
|
510 |
+
* updates page.
|
511 |
+
*
|
512 |
+
* @author Leo Fajardo (@leorw)
|
513 |
+
* @since 2.3.1
|
514 |
+
*/
|
515 |
+
$this->_update_details = null;
|
516 |
+
$current_plugin_version = $this->_fs->get_plugin_version( true );
|
517 |
+
}
|
518 |
+
}
|
519 |
+
|
520 |
+
if ( ! isset( $this->_update_details ) ) {
|
521 |
+
// Get plugin's newest update.
|
522 |
+
$new_version = $this->_fs->get_update(
|
523 |
+
false,
|
524 |
+
fs_request_get_bool( 'force-check' ),
|
525 |
+
WP_FS__TIME_24_HOURS_IN_SEC / 24,
|
526 |
+
$current_plugin_version
|
527 |
+
);
|
528 |
+
|
529 |
+
$this->_update_details = false;
|
530 |
+
|
531 |
+
if ( is_object( $new_version ) && $this->is_new_version_premium( $new_version ) ) {
|
532 |
+
$this->_logger->log( 'Found newer plugin version ' . $new_version->version );
|
533 |
+
|
534 |
+
/**
|
535 |
+
* Cache plugin details locally since set_site_transient( 'update_plugins' )
|
536 |
+
* called multiple times and the non wp.org plugins are filtered after the
|
537 |
+
* call to .org.
|
538 |
+
*
|
539 |
+
* @since 1.1.8.1
|
540 |
+
*/
|
541 |
+
$this->_update_details = $this->get_update_details( $new_version );
|
542 |
+
}
|
543 |
+
}
|
544 |
+
|
545 |
+
// Alias.
|
546 |
+
$basename = $this->_fs->premium_plugin_basename();
|
547 |
+
|
548 |
+
if ( is_object( $this->_update_details ) ) {
|
549 |
+
if ( isset( $transient_data->no_update ) ) {
|
550 |
+
unset( $transient_data->no_update[ $basename ] );
|
551 |
+
}
|
552 |
+
|
553 |
+
if ( ! isset( $transient_data->response ) ) {
|
554 |
+
$transient_data->response = array();
|
555 |
+
}
|
556 |
+
|
557 |
+
// Add plugin to transient data.
|
558 |
+
$transient_data->response[ $basename ] = $this->_fs->is_plugin() ?
|
559 |
+
$this->_update_details :
|
560 |
+
(array) $this->_update_details;
|
561 |
+
} else {
|
562 |
+
if ( isset( $transient_data->response ) ) {
|
563 |
+
/**
|
564 |
+
* Ensure that there's no update data for the plugin to prevent upgrading the premium version to the latest free version.
|
565 |
+
*
|
566 |
+
* @author Leo Fajardo (@leorw)
|
567 |
+
* @since 2.3.0
|
568 |
+
*/
|
569 |
+
unset( $transient_data->response[ $basename ] );
|
570 |
+
}
|
571 |
+
|
572 |
+
if ( ! isset( $transient_data->no_update ) ) {
|
573 |
+
$transient_data->no_update = array();
|
574 |
+
}
|
575 |
+
|
576 |
+
/**
|
577 |
+
* Add product to no_update transient data to properly integrate with WP 5.5 auto-updates UI.
|
578 |
+
*
|
579 |
+
* @since 2.4.1
|
580 |
+
* @link https://make.wordpress.org/core/2020/07/30/recommended-usage-of-the-updates-api-to-support-the-auto-updates-ui-for-plugins-and-themes-in-wordpress-5-5/
|
581 |
+
*/
|
582 |
+
$transient_data->no_update[ $basename ] = $this->_fs->is_plugin() ?
|
583 |
+
(object) array(
|
584 |
+
'id' => $basename,
|
585 |
+
'slug' => $this->_fs->get_slug(),
|
586 |
+
'plugin' => $basename,
|
587 |
+
'new_version' => $this->_fs->get_plugin_version(),
|
588 |
+
'url' => '',
|
589 |
+
'package' => '',
|
590 |
+
'icons' => array(),
|
591 |
+
'banners' => array(),
|
592 |
+
'banners_rtl' => array(),
|
593 |
+
'tested' => '',
|
594 |
+
'requires_php' => '',
|
595 |
+
'compatibility' => new stdClass(),
|
596 |
+
) :
|
597 |
+
array(
|
598 |
+
'theme' => $basename,
|
599 |
+
'new_version' => $this->_fs->get_plugin_version(),
|
600 |
+
'url' => '',
|
601 |
+
'package' => '',
|
602 |
+
'requires' => '',
|
603 |
+
'requires_php' => '',
|
604 |
+
);
|
605 |
+
}
|
606 |
+
|
607 |
+
$slug = $this->_fs->get_slug();
|
608 |
+
|
609 |
+
if ( $this->_fs->is_org_repo_compliant() && $this->_fs->is_freemium() ) {
|
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 |
+
|
621 |
+
if ( ! empty( $this->_translation_updates ) ) {
|
622 |
+
$all_translation_updates = ( isset( $transient_data->translations ) && is_array( $transient_data->translations ) ) ?
|
623 |
+
$transient_data->translations :
|
624 |
+
array();
|
625 |
+
|
626 |
+
$current_plugin_translation_updates_map = array();
|
627 |
+
foreach ( $all_translation_updates as $key => $translation_update ) {
|
628 |
+
if ( $module_type === ( $translation_update['type'] . 's' ) && $slug === $translation_update['slug'] ) {
|
629 |
+
$current_plugin_translation_updates_map[ $translation_update['language'] ] = $translation_update;
|
630 |
+
unset( $all_translation_updates[ $key ] );
|
631 |
+
}
|
632 |
+
}
|
633 |
+
|
634 |
+
foreach ( $this->_translation_updates as $translation_update ) {
|
635 |
+
$lang = $translation_update['language'];
|
636 |
+
if ( ! isset( $current_plugin_translation_updates_map[ $lang ] ) ||
|
637 |
+
version_compare( $translation_update['version'], $current_plugin_translation_updates_map[ $lang ]['version'], '>' )
|
638 |
+
) {
|
639 |
+
$current_plugin_translation_updates_map[ $lang ] = $translation_update;
|
640 |
+
}
|
641 |
+
}
|
642 |
+
|
643 |
+
$transient_data->translations = array_merge( $all_translation_updates, array_values( $current_plugin_translation_updates_map ) );
|
644 |
+
}
|
645 |
+
}
|
646 |
+
|
647 |
+
return $transient_data;
|
648 |
+
}
|
649 |
+
|
650 |
+
/**
|
651 |
+
* Get module's required data for the updates mechanism.
|
652 |
+
*
|
653 |
+
* @author Vova Feldman (@svovaf)
|
654 |
+
* @since 2.0.0
|
655 |
+
*
|
656 |
+
* @param \FS_Plugin_Tag $new_version
|
657 |
+
*
|
658 |
+
* @return object
|
659 |
+
*/
|
660 |
+
function get_update_details( FS_Plugin_Tag $new_version ) {
|
661 |
+
$update = new stdClass();
|
662 |
+
$update->slug = $this->_fs->get_slug();
|
663 |
+
$update->new_version = $new_version->version;
|
664 |
+
$update->url = WP_FS__ADDRESS;
|
665 |
+
$update->package = $new_version->url;
|
666 |
+
$update->tested = $new_version->tested_up_to_version;
|
667 |
+
$update->requires = $new_version->requires_platform_version;
|
668 |
+
|
669 |
+
$icon = $this->_fs->get_local_icon_url();
|
670 |
+
|
671 |
+
if ( ! empty( $icon ) ) {
|
672 |
+
$update->icons = array(
|
673 |
+
// '1x' => $icon,
|
674 |
+
// '2x' => $icon,
|
675 |
+
'default' => $icon,
|
676 |
+
);
|
677 |
+
}
|
678 |
+
|
679 |
+
if ( $this->_fs->is_premium() ) {
|
680 |
+
$latest_tag = $this->_fs->_fetch_latest_version( $this->_fs->get_id(), false );
|
681 |
+
|
682 |
+
if (
|
683 |
+
isset( $latest_tag->readme ) &&
|
684 |
+
isset( $latest_tag->readme->upgrade_notice ) &&
|
685 |
+
! empty( $latest_tag->readme->upgrade_notice )
|
686 |
+
) {
|
687 |
+
$update->upgrade_notice = $latest_tag->readme->upgrade_notice;
|
688 |
+
}
|
689 |
+
}
|
690 |
+
|
691 |
+
$update->{$this->_fs->get_module_type()} = $this->_fs->get_plugin_basename();
|
692 |
+
|
693 |
+
return $update;
|
694 |
+
}
|
695 |
+
|
696 |
+
/**
|
697 |
+
* @author Leo Fajardo (@leorw)
|
698 |
+
* @since 2.3.0
|
699 |
+
*
|
700 |
+
* @param FS_Plugin_Tag $new_version
|
701 |
+
*
|
702 |
+
* @return bool
|
703 |
+
*/
|
704 |
+
private function is_new_version_premium( FS_Plugin_Tag $new_version ) {
|
705 |
+
$query_str = parse_url( $new_version->url, PHP_URL_QUERY );
|
706 |
+
if ( empty( $query_str ) ) {
|
707 |
+
return false;
|
708 |
+
}
|
709 |
+
|
710 |
+
parse_str( $query_str, $params );
|
711 |
+
|
712 |
+
return ( isset( $params['is_premium'] ) && 'true' == $params['is_premium'] );
|
713 |
+
}
|
714 |
+
|
715 |
+
/**
|
716 |
+
* Update the updates transient with the module's update information.
|
717 |
+
*
|
718 |
+
* This method is required for multisite environment.
|
719 |
+
* If a module is site activated (not network) and not on the main site,
|
720 |
+
* the module will NOT be executed on the network level, therefore, the
|
721 |
+
* custom updates logic will not be executed as well, so unless we force
|
722 |
+
* the injection of the update into the updates transient, premium updates
|
723 |
+
* will not work.
|
724 |
+
*
|
725 |
+
* @author Vova Feldman (@svovaf)
|
726 |
+
* @since 2.0.0
|
727 |
+
*
|
728 |
+
* @param \FS_Plugin_Tag $new_version
|
729 |
+
*/
|
730 |
+
function set_update_data( FS_Plugin_Tag $new_version ) {
|
731 |
+
$this->_logger->entrance();
|
732 |
+
|
733 |
+
if ( ! $this->is_new_version_premium( $new_version ) ) {
|
734 |
+
return;
|
735 |
+
}
|
736 |
+
|
737 |
+
$transient_key = "update_{$this->_fs->get_module_type()}s";
|
738 |
+
|
739 |
+
$transient_data = get_site_transient( $transient_key );
|
740 |
+
|
741 |
+
$transient_data = is_object( $transient_data ) ?
|
742 |
+
$transient_data :
|
743 |
+
new stdClass();
|
744 |
+
|
745 |
+
// Alias.
|
746 |
+
$basename = $this->_fs->get_plugin_basename();
|
747 |
+
$is_plugin = $this->_fs->is_plugin();
|
748 |
+
|
749 |
+
if ( ! isset( $transient_data->response ) ||
|
750 |
+
! is_array( $transient_data->response )
|
751 |
+
) {
|
752 |
+
$transient_data->response = array();
|
753 |
+
} else if ( ! empty( $transient_data->response[ $basename ] ) ) {
|
754 |
+
$version = $is_plugin ?
|
755 |
+
( ! empty( $transient_data->response[ $basename ]->new_version ) ?
|
756 |
+
$transient_data->response[ $basename ]->new_version :
|
757 |
+
null
|
758 |
+
) : ( ! empty( $transient_data->response[ $basename ]['new_version'] ) ?
|
759 |
+
$transient_data->response[ $basename ]['new_version'] :
|
760 |
+
null
|
761 |
+
);
|
762 |
+
|
763 |
+
if ( $version == $new_version->version ) {
|
764 |
+
// The update data is already set.
|
765 |
+
return;
|
766 |
+
}
|
767 |
+
}
|
768 |
+
|
769 |
+
// Remove the added filters.
|
770 |
+
$this->remove_transient_filters();
|
771 |
+
|
772 |
+
$this->_update_details = $this->get_update_details( $new_version );
|
773 |
+
|
774 |
+
// Set update data in transient.
|
775 |
+
$transient_data->response[ $basename ] = $is_plugin ?
|
776 |
+
$this->_update_details :
|
777 |
+
(array) $this->_update_details;
|
778 |
+
|
779 |
+
if ( ! isset( $transient_data->checked ) ||
|
780 |
+
! is_array( $transient_data->checked )
|
781 |
+
) {
|
782 |
+
$transient_data->checked = array();
|
783 |
+
}
|
784 |
+
|
785 |
+
// Flag the module as if it was already checked.
|
786 |
+
$transient_data->checked[ $basename ] = $this->_fs->get_plugin_version();
|
787 |
+
$transient_data->last_checked = time();
|
788 |
+
|
789 |
+
set_site_transient( $transient_key, $transient_data );
|
790 |
+
|
791 |
+
$this->add_transient_filters();
|
792 |
+
}
|
793 |
+
|
794 |
+
/**
|
795 |
+
* @author Leo Fajardo (@leorw)
|
796 |
+
* @since 2.0.2
|
797 |
+
*/
|
798 |
+
function delete_update_data() {
|
799 |
+
$this->_logger->entrance();
|
800 |
+
|
801 |
+
$transient_key = "update_{$this->_fs->get_module_type()}s";
|
802 |
+
|
803 |
+
$transient_data = get_site_transient( $transient_key );
|
804 |
+
|
805 |
+
// Alias
|
806 |
+
$basename = $this->_fs->get_plugin_basename();
|
807 |
+
|
808 |
+
if ( ! is_object( $transient_data ) ||
|
809 |
+
! isset( $transient_data->response ) ||
|
810 |
+
! is_array( $transient_data->response ) ||
|
811 |
+
empty( $transient_data->response[ $basename ] )
|
812 |
+
) {
|
813 |
+
return;
|
814 |
+
}
|
815 |
+
|
816 |
+
unset( $transient_data->response[ $basename ] );
|
817 |
+
|
818 |
+
// Remove the added filters.
|
819 |
+
$this->remove_transient_filters();
|
820 |
+
|
821 |
+
set_site_transient( $transient_key, $transient_data );
|
822 |
+
|
823 |
+
$this->add_transient_filters();
|
824 |
+
}
|
825 |
+
|
826 |
+
/**
|
827 |
+
* Try to fetch plugin's info from .org repository.
|
828 |
+
*
|
829 |
+
* @author Vova Feldman (@svovaf)
|
830 |
+
* @since 1.0.5
|
831 |
+
*
|
832 |
+
* @param string $action
|
833 |
+
* @param object $args
|
834 |
+
*
|
835 |
+
* @return bool|mixed
|
836 |
+
*/
|
837 |
+
static function _fetch_plugin_info_from_repository( $action, $args ) {
|
838 |
+
$url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
|
839 |
+
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
|
840 |
+
$url = set_url_scheme( $url, 'https' );
|
841 |
+
}
|
842 |
+
|
843 |
+
$args = array(
|
844 |
+
'timeout' => 15,
|
845 |
+
'body' => array(
|
846 |
+
'action' => $action,
|
847 |
+
'request' => serialize( $args )
|
848 |
+
)
|
849 |
+
);
|
850 |
+
|
851 |
+
$request = wp_remote_post( $url, $args );
|
852 |
+
|
853 |
+
if ( is_wp_error( $request ) ) {
|
854 |
+
return false;
|
855 |
+
}
|
856 |
+
|
857 |
+
$res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
|
858 |
+
|
859 |
+
if ( ! is_object( $res ) && ! is_array( $res ) ) {
|
860 |
+
return false;
|
861 |
+
}
|
862 |
+
|
863 |
+
return $res;
|
864 |
+
}
|
865 |
+
|
866 |
+
/**
|
867 |
+
* Fetches module translation updates from wordpress.org.
|
868 |
+
*
|
869 |
+
* @author Leo Fajardo (@leorw)
|
870 |
+
* @since 2.1.2
|
871 |
+
*
|
872 |
+
* @param string $module_type
|
873 |
+
* @param string $slug
|
874 |
+
*
|
875 |
+
* @return array|null
|
876 |
+
*/
|
877 |
+
private function fetch_wp_org_module_translation_updates( $module_type, $slug ) {
|
878 |
+
$plugin_data = $this->_fs->get_plugin_data();
|
879 |
+
|
880 |
+
$locales = array_values( get_available_languages() );
|
881 |
+
$locales = apply_filters( "{$module_type}_update_check_locales", $locales );
|
882 |
+
$locales = array_unique( $locales );
|
883 |
+
|
884 |
+
$plugin_basename = $this->_fs->get_plugin_basename();
|
885 |
+
if ( 'themes' === $module_type ) {
|
886 |
+
$plugin_basename = $slug;
|
887 |
+
}
|
888 |
+
|
889 |
+
global $wp_version;
|
890 |
+
|
891 |
+
$request_args = array(
|
892 |
+
'timeout' => 15,
|
893 |
+
'body' => array(
|
894 |
+
"{$module_type}" => json_encode(
|
895 |
+
array(
|
896 |
+
"{$module_type}" => array(
|
897 |
+
$plugin_basename => array(
|
898 |
+
'Name' => trim( str_replace( $this->_fs->get_plugin()->premium_suffix, '', $plugin_data['Name'] ) ),
|
899 |
+
'Author' => $plugin_data['Author'],
|
900 |
+
)
|
901 |
+
)
|
902 |
+
)
|
903 |
+
),
|
904 |
+
'translations' => json_encode( $this->get_installed_translations( $module_type, $slug ) ),
|
905 |
+
'locale' => json_encode( $locales )
|
906 |
+
),
|
907 |
+
'user-agent' => ( 'WordPress/' . $wp_version . '; ' . home_url( '/' ) )
|
908 |
+
);
|
909 |
+
|
910 |
+
$url = "http://api.wordpress.org/{$module_type}/update-check/1.1/";
|
911 |
+
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
|
912 |
+
$url = set_url_scheme( $url, 'https' );
|
913 |
+
}
|
914 |
+
|
915 |
+
$raw_response = Freemius::safe_remote_post(
|
916 |
+
$url,
|
917 |
+
$request_args,
|
918 |
+
WP_FS__TIME_24_HOURS_IN_SEC,
|
919 |
+
WP_FS__TIME_12_HOURS_IN_SEC,
|
920 |
+
false
|
921 |
+
);
|
922 |
+
|
923 |
+
if ( is_wp_error( $raw_response ) ) {
|
924 |
+
return null;
|
925 |
+
}
|
926 |
+
|
927 |
+
$response = json_decode( wp_remote_retrieve_body( $raw_response ), true );
|
928 |
+
|
929 |
+
if ( ! is_array( $response ) ) {
|
930 |
+
return null;
|
931 |
+
}
|
932 |
+
|
933 |
+
if ( ! isset( $response['translations'] ) || empty( $response['translations'] ) ) {
|
934 |
+
return null;
|
935 |
+
}
|
936 |
+
|
937 |
+
return $response['translations'];
|
938 |
+
}
|
939 |
+
|
940 |
+
/**
|
941 |
+
* @author Leo Fajardo (@leorw)
|
942 |
+
* @since 2.1.2
|
943 |
+
*
|
944 |
+
* @param string $module_type
|
945 |
+
* @param string $slug
|
946 |
+
*
|
947 |
+
* @return array
|
948 |
+
*/
|
949 |
+
private function get_installed_translations( $module_type, $slug ) {
|
950 |
+
if ( function_exists( 'wp_get_installed_translations' ) ) {
|
951 |
+
return wp_get_installed_translations( $module_type );
|
952 |
+
}
|
953 |
+
|
954 |
+
$dir = "/{$module_type}";
|
955 |
+
|
956 |
+
if ( ! is_dir( WP_LANG_DIR . $dir ) )
|
957 |
+
return array();
|
958 |
+
|
959 |
+
$files = scandir( WP_LANG_DIR . $dir );
|
960 |
+
if ( ! $files )
|
961 |
+
return array();
|
962 |
+
|
963 |
+
$language_data = array();
|
964 |
+
|
965 |
+
foreach ( $files as $file ) {
|
966 |
+
if ( 0 !== strpos( $file, $slug ) ) {
|
967 |
+
continue;
|
968 |
+
}
|
969 |
+
|
970 |
+
if ( '.' === $file[0] || is_dir( WP_LANG_DIR . "{$dir}/{$file}" ) ) {
|
971 |
+
continue;
|
972 |
+
}
|
973 |
+
|
974 |
+
if ( substr( $file, -3 ) !== '.po' ) {
|
975 |
+
continue;
|
976 |
+
}
|
977 |
+
|
978 |
+
if ( ! preg_match( '/(?:(.+)-)?([a-z]{2,3}(?:_[A-Z]{2})?(?:_[a-z0-9]+)?).po/', $file, $match ) ) {
|
979 |
+
continue;
|
980 |
+
}
|
981 |
+
|
982 |
+
if ( ! in_array( substr( $file, 0, -3 ) . '.mo', $files ) ) {
|
983 |
+
continue;
|
984 |
+
}
|
985 |
+
|
986 |
+
list( , $textdomain, $language ) = $match;
|
987 |
+
|
988 |
+
if ( '' === $textdomain ) {
|
989 |
+
$textdomain = 'default';
|
990 |
+
}
|
991 |
+
|
992 |
+
$language_data[ $textdomain ][ $language ] = wp_get_pomo_file_data( WP_LANG_DIR . "{$dir}/{$file}" );
|
993 |
+
}
|
994 |
+
|
995 |
+
return $language_data;
|
996 |
+
}
|
997 |
+
|
998 |
+
/**
|
999 |
+
* Updates information on the "View version x.x details" page with custom data.
|
1000 |
+
*
|
1001 |
+
* @author Vova Feldman (@svovaf)
|
1002 |
+
* @since 1.0.4
|
1003 |
+
*
|
1004 |
+
* @uses FS_Api
|
1005 |
+
*
|
1006 |
+
* @param object $data
|
1007 |
+
* @param string $action
|
1008 |
+
* @param mixed $args
|
1009 |
+
*
|
1010 |
+
* @return object
|
1011 |
+
*/
|
1012 |
+
function plugins_api_filter( $data, $action = '', $args = null ) {
|
1013 |
+
$this->_logger->entrance();
|
1014 |
+
|
1015 |
+
if ( ( 'plugin_information' !== $action ) ||
|
1016 |
+
! isset( $args->slug )
|
1017 |
+
) {
|
1018 |
+
return $data;
|
1019 |
+
}
|
1020 |
+
|
1021 |
+
$addon = false;
|
1022 |
+
$is_addon = false;
|
1023 |
+
$addon_version = false;
|
1024 |
+
|
1025 |
+
if ( $this->_fs->get_slug() !== $args->slug ) {
|
1026 |
+
$addon = $this->_fs->get_addon_by_slug( $args->slug );
|
1027 |
+
|
1028 |
+
if ( ! is_object( $addon ) ) {
|
1029 |
+
return $data;
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
if ( $this->_fs->is_addon_activated( $addon->id ) ) {
|
1033 |
+
$addon_version = $this->_fs->get_addon_instance( $addon->id )->get_plugin_version();
|
1034 |
+
} else if ( $this->_fs->is_addon_installed( $addon->id ) ) {
|
1035 |
+
$addon_plugin_data = get_plugin_data(
|
1036 |
+
( WP_PLUGIN_DIR . '/' . $this->_fs->get_addon_basename( $addon->id ) ),
|
1037 |
+
false,
|
1038 |
+
false
|
1039 |
+
);
|
1040 |
+
|
1041 |
+
if ( ! empty( $addon_plugin_data ) ) {
|
1042 |
+
$addon_version = $addon_plugin_data['Version'];
|
1043 |
+
}
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
$is_addon = true;
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
$plugin_in_repo = false;
|
1050 |
+
if ( ! $is_addon ) {
|
1051 |
+
// Try to fetch info from .org repository.
|
1052 |
+
$data = self::_fetch_plugin_info_from_repository( $action, $args );
|
1053 |
+
|
1054 |
+
$plugin_in_repo = ( false !== $data );
|
1055 |
+
}
|
1056 |
+
|
1057 |
+
if ( ! $plugin_in_repo ) {
|
1058 |
+
$data = $args;
|
1059 |
+
|
1060 |
+
// Fetch as much as possible info from local files.
|
1061 |
+
$plugin_local_data = $this->_fs->get_plugin_data();
|
1062 |
+
$data->name = $plugin_local_data['Name'];
|
1063 |
+
$data->author = $plugin_local_data['Author'];
|
1064 |
+
$data->sections = array(
|
1065 |
+
'description' => 'Upgrade ' . $plugin_local_data['Name'] . ' to latest.',
|
1066 |
+
);
|
1067 |
+
|
1068 |
+
// @todo Store extra plugin info on Freemius or parse readme.txt markup.
|
1069 |
+
/*$info = $this->_fs->get_api_site_scope()->call('/information.json');
|
1070 |
+
|
1071 |
+
if ( !isset($info->error) ) {
|
1072 |
+
$data = $info;
|
1073 |
+
}*/
|
1074 |
+
}
|
1075 |
+
|
1076 |
+
$plugin_version = $is_addon ?
|
1077 |
+
$addon_version :
|
1078 |
+
$this->_fs->get_plugin_version();
|
1079 |
+
|
1080 |
+
// Get plugin's newest update.
|
1081 |
+
$new_version = $this->get_latest_download_details( $is_addon ? $addon->id : false, $plugin_version );
|
1082 |
+
|
1083 |
+
if ( ! is_object( $new_version ) || empty( $new_version->version ) ) {
|
1084 |
+
$data->version = $plugin_version;
|
1085 |
+
} else {
|
1086 |
+
if ( $is_addon ) {
|
1087 |
+
$data->name = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
|
1088 |
+
$data->slug = $addon->slug;
|
1089 |
+
$data->url = WP_FS__ADDRESS;
|
1090 |
+
$data->package = $new_version->url;
|
1091 |
+
}
|
1092 |
+
|
1093 |
+
if ( ! $plugin_in_repo ) {
|
1094 |
+
$data->last_updated = ! is_null( $new_version->updated ) ? $new_version->updated : $new_version->created;
|
1095 |
+
$data->requires = $new_version->requires_platform_version;
|
1096 |
+
$data->tested = $new_version->tested_up_to_version;
|
1097 |
+
}
|
1098 |
+
|
1099 |
+
$data->version = $new_version->version;
|
1100 |
+
$data->download_link = $new_version->url;
|
1101 |
+
|
1102 |
+
if ( isset( $new_version->readme ) && is_object( $new_version->readme ) ) {
|
1103 |
+
$new_version_readme_data = $new_version->readme;
|
1104 |
+
if ( isset( $new_version_readme_data->sections ) ) {
|
1105 |
+
$new_version_readme_data->sections = (array) $new_version_readme_data->sections;
|
1106 |
+
} else {
|
1107 |
+
$new_version_readme_data->sections = array();
|
1108 |
+
}
|
1109 |
+
|
1110 |
+
if ( isset( $data->sections ) ) {
|
1111 |
+
if ( isset( $data->sections['screenshots'] ) ) {
|
1112 |
+
$new_version_readme_data->sections['screenshots'] = $data->sections['screenshots'];
|
1113 |
+
}
|
1114 |
+
|
1115 |
+
if ( isset( $data->sections['reviews'] ) ) {
|
1116 |
+
$new_version_readme_data->sections['reviews'] = $data->sections['reviews'];
|
1117 |
+
}
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
if ( isset( $new_version_readme_data->banners ) ) {
|
1121 |
+
$new_version_readme_data->banners = (array) $new_version_readme_data->banners;
|
1122 |
+
} else if ( isset( $data->banners ) ) {
|
1123 |
+
$new_version_readme_data->banners = $data->banners;
|
1124 |
+
}
|
1125 |
+
|
1126 |
+
$wp_org_sections = array(
|
1127 |
+
'author',
|
1128 |
+
'author_profile',
|
1129 |
+
'rating',
|
1130 |
+
'ratings',
|
1131 |
+
'num_ratings',
|
1132 |
+
'support_threads',
|
1133 |
+
'support_threads_resolved',
|
1134 |
+
'active_installs',
|
1135 |
+
'added',
|
1136 |
+
'homepage'
|
1137 |
+
);
|
1138 |
+
|
1139 |
+
foreach ( $wp_org_sections as $wp_org_section ) {
|
1140 |
+
if ( isset( $data->{$wp_org_section} ) ) {
|
1141 |
+
$new_version_readme_data->{$wp_org_section} = $data->{$wp_org_section};
|
1142 |
+
}
|
1143 |
+
}
|
1144 |
+
|
1145 |
+
$data = $new_version_readme_data;
|
1146 |
+
}
|
1147 |
+
}
|
1148 |
+
|
1149 |
+
return $data;
|
1150 |
+
}
|
1151 |
+
|
1152 |
+
/**
|
1153 |
+
* @author Vova Feldman (@svovaf)
|
1154 |
+
* @since 1.2.1.7
|
1155 |
+
*
|
1156 |
+
* @param number|bool $addon_id
|
1157 |
+
* @param bool|string $newer_than Since 2.2.1
|
1158 |
+
* @param bool|string $fetch_readme Since 2.2.1
|
1159 |
+
*
|
1160 |
+
* @return object
|
1161 |
+
*/
|
1162 |
+
private function get_latest_download_details( $addon_id = false, $newer_than = false, $fetch_readme = true ) {
|
1163 |
+
return $this->_fs->_fetch_latest_version( $addon_id, true, WP_FS__TIME_24_HOURS_IN_SEC, $newer_than, $fetch_readme );
|
1164 |
+
}
|
1165 |
+
|
1166 |
+
/**
|
1167 |
+
* Checks if a given basename has a matching folder name
|
1168 |
+
* with the current context plugin.
|
1169 |
+
*
|
1170 |
+
* @author Vova Feldman (@svovaf)
|
1171 |
+
* @since 1.2.1.6
|
1172 |
+
*
|
1173 |
+
* @return bool
|
1174 |
+
*/
|
1175 |
+
private function is_correct_folder_name() {
|
1176 |
+
return ( $this->_fs->get_target_folder_name() == trim( dirname( $this->_fs->get_plugin_basename() ), '/\\' ) );
|
1177 |
+
}
|
1178 |
+
|
1179 |
+
/**
|
1180 |
+
* This is a special after upgrade handler for migrating modules
|
1181 |
+
* that didn't use the '-premium' suffix folder structure before
|
1182 |
+
* the migration.
|
1183 |
+
*
|
1184 |
+
* @author Vova Feldman (@svovaf)
|
1185 |
+
* @since 1.2.1.6
|
1186 |
+
*
|
1187 |
+
* @param bool $response Install response.
|
1188 |
+
* @param array $hook_extra Extra arguments passed to hooked filters.
|
1189 |
+
* @param array $result Installation result data.
|
1190 |
+
*
|
1191 |
+
* @return bool
|
1192 |
+
*/
|
1193 |
+
function _maybe_update_folder_name( $response, $hook_extra, $result ) {
|
1194 |
+
$basename = $this->_fs->get_plugin_basename();
|
1195 |
+
|
1196 |
+
if ( true !== $response ||
|
1197 |
+
empty( $hook_extra ) ||
|
1198 |
+
empty( $hook_extra['plugin'] ) ||
|
1199 |
+
$basename !== $hook_extra['plugin']
|
1200 |
+
) {
|
1201 |
+
return $response;
|
1202 |
+
}
|
1203 |
+
|
1204 |
+
$active_plugins_basenames = get_option( 'active_plugins' );
|
1205 |
+
|
1206 |
+
foreach ( $active_plugins_basenames as $key => $active_plugin_basename ) {
|
1207 |
+
if ( $basename === $active_plugin_basename ) {
|
1208 |
+
// Get filename including extension.
|
1209 |
+
$filename = basename( $basename );
|
1210 |
+
|
1211 |
+
$new_basename = plugin_basename(
|
1212 |
+
trailingslashit( $this->_fs->is_premium() ? $this->_fs->get_premium_slug() : $this->_fs->get_slug() ) .
|
1213 |
+
$filename
|
1214 |
+
);
|
1215 |
+
|
1216 |
+
// Verify that the expected correct path exists.
|
1217 |
+
if ( file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $new_basename ) ) ) {
|
1218 |
+
// Override active plugin name.
|
1219 |
+
$active_plugins_basenames[ $key ] = $new_basename;
|
1220 |
+
update_option( 'active_plugins', $active_plugins_basenames );
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
break;
|
1224 |
+
}
|
1225 |
+
}
|
1226 |
+
|
1227 |
+
return $response;
|
1228 |
+
}
|
1229 |
+
|
1230 |
+
#----------------------------------------------------------------------------------
|
1231 |
+
#region Auto Activation
|
1232 |
+
#----------------------------------------------------------------------------------
|
1233 |
+
|
1234 |
+
/**
|
1235 |
+
* Installs and active a plugin when explicitly requested that from a 3rd party service.
|
1236 |
+
*
|
1237 |
+
* This logic was inspired by the TGMPA GPL licensed library by Thomas Griffin.
|
1238 |
+
*
|
1239 |
+
* @link http://tgmpluginactivation.com/
|
1240 |
+
*
|
1241 |
+
* @author Vova Feldman
|
1242 |
+
* @since 1.2.1.7
|
1243 |
+
*
|
1244 |
+
* @link https://make.wordpress.org/plugins/2017/03/16/clarification-of-guideline-8-executable-code-and-installs/
|
1245 |
+
*
|
1246 |
+
* @uses WP_Filesystem
|
1247 |
+
* @uses WP_Error
|
1248 |
+
* @uses WP_Upgrader
|
1249 |
+
* @uses Plugin_Upgrader
|
1250 |
+
* @uses Plugin_Installer_Skin
|
1251 |
+
* @uses Plugin_Upgrader_Skin
|
1252 |
+
*
|
1253 |
+
* @param number|bool $plugin_id
|
1254 |
+
*
|
1255 |
+
* @return array
|
1256 |
+
*/
|
1257 |
+
function install_and_activate_plugin( $plugin_id = false ) {
|
1258 |
+
if ( ! empty( $plugin_id ) && ! FS_Plugin::is_valid_id( $plugin_id ) ) {
|
1259 |
+
// Invalid plugin ID.
|
1260 |
+
return array(
|
1261 |
+
'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ),
|
1262 |
+
'code' => 'invalid_module_id',
|
1263 |
+
);
|
1264 |
+
}
|
1265 |
+
|
1266 |
+
$is_addon = false;
|
1267 |
+
if ( FS_Plugin::is_valid_id( $plugin_id ) &&
|
1268 |
+
$plugin_id != $this->_fs->get_id()
|
1269 |
+
) {
|
1270 |
+
$addon = $this->_fs->get_addon( $plugin_id );
|
1271 |
+
|
1272 |
+
if ( ! is_object( $addon ) ) {
|
1273 |
+
// Invalid add-on ID.
|
1274 |
+
return array(
|
1275 |
+
'message' => $this->_fs->get_text_inline( 'Invalid module ID.', 'auto-install-error-invalid-id' ),
|
1276 |
+
'code' => 'invalid_module_id',
|
1277 |
+
);
|
1278 |
+
}
|
1279 |
+
|
1280 |
+
$slug = $addon->slug;
|
1281 |
+
$premium_slug = $addon->premium_slug;
|
1282 |
+
$title = $addon->title . ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' );
|
1283 |
+
|
1284 |
+
$is_addon = true;
|
1285 |
+
} else {
|
1286 |
+
$slug = $this->_fs->get_slug();
|
1287 |
+
$premium_slug = $this->_fs->get_premium_slug();
|
1288 |
+
$title = $this->_fs->get_plugin_title() .
|
1289 |
+
( $this->_fs->is_addon() ? ' ' . $this->_fs->get_text_inline( 'Add-On', 'addon' ) : '' );
|
1290 |
+
}
|
1291 |
+
|
1292 |
+
if ( $this->is_premium_plugin_active( $plugin_id ) ) {
|
1293 |
+
// Premium version already activated.
|
1294 |
+
return array(
|
1295 |
+
'message' => $is_addon ?
|
1296 |
+
$this->_fs->get_text_inline( 'Premium add-on version already installed.', 'auto-install-error-premium-addon-activated' ) :
|
1297 |
+
$this->_fs->get_text_inline( 'Premium version already active.', 'auto-install-error-premium-activated' ),
|
1298 |
+
'code' => 'premium_installed',
|
1299 |
+
);
|
1300 |
+
}
|
1301 |
+
|
1302 |
+
$latest_version = $this->get_latest_download_details( $plugin_id, false, false );
|
1303 |
+
$target_folder = $premium_slug;
|
1304 |
+
|
1305 |
+
// Prep variables for Plugin_Installer_Skin class.
|
1306 |
+
$extra = array();
|
1307 |
+
$extra['slug'] = $target_folder;
|
1308 |
+
$source = $latest_version->url;
|
1309 |
+
$api = null;
|
1310 |
+
|
1311 |
+
$install_url = add_query_arg(
|
1312 |
+
array(
|
1313 |
+
'action' => 'install-plugin',
|
1314 |
+
'plugin' => urlencode( $slug ),
|
1315 |
+
),
|
1316 |
+
'update.php'
|
1317 |
+
);
|
1318 |
+
|
1319 |
+
if ( ! class_exists( 'Plugin_Upgrader', false ) ) {
|
1320 |
+
// Include required resources for the installation.
|
1321 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
|
1322 |
+
}
|
1323 |
+
|
1324 |
+
$skin_args = array(
|
1325 |
+
'type' => 'web',
|
1326 |
+
'title' => sprintf( $this->_fs->get_text_inline( 'Installing plugin: %s', 'installing-plugin-x' ), $title ),
|
1327 |
+
'url' => esc_url_raw( $install_url ),
|
1328 |
+
'nonce' => 'install-plugin_' . $slug,
|
1329 |
+
'plugin' => '',
|
1330 |
+
'api' => $api,
|
1331 |
+
'extra' => $extra,
|
1332 |
+
);
|
1333 |
+
|
1334 |
+
// $skin = new Automatic_Upgrader_Skin( $skin_args );
|
1335 |
+
// $skin = new Plugin_Installer_Skin( $skin_args );
|
1336 |
+
$skin = new WP_Ajax_Upgrader_Skin( $skin_args );
|
1337 |
+
|
1338 |
+
// Create a new instance of Plugin_Upgrader.
|
1339 |
+
$upgrader = new Plugin_Upgrader( $skin );
|
1340 |
+
|
1341 |
+
// Perform the action and install the plugin from the $source urldecode().
|
1342 |
+
add_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1, 3 );
|
1343 |
+
|
1344 |
+
$install_result = $upgrader->install( $source );
|
1345 |
+
|
1346 |
+
remove_filter( 'upgrader_source_selection', array( 'FS_Plugin_Updater', '_maybe_adjust_source_dir' ), 1 );
|
1347 |
+
|
1348 |
+
if ( is_wp_error( $install_result ) ) {
|
1349 |
+
return array(
|
1350 |
+
'message' => $install_result->get_error_message(),
|
1351 |
+
'code' => $install_result->get_error_code(),
|
1352 |
+
);
|
1353 |
+
} elseif ( is_wp_error( $skin->result ) ) {
|
1354 |
+
return array(
|
1355 |
+
'message' => $skin->result->get_error_message(),
|
1356 |
+
'code' => $skin->result->get_error_code(),
|
1357 |
+
);
|
1358 |
+
} elseif ( $skin->get_errors()->get_error_code() ) {
|
1359 |
+
return array(
|
1360 |
+
'message' => $skin->get_error_messages(),
|
1361 |
+
'code' => 'unknown',
|
1362 |
+
);
|
1363 |
+
} elseif ( is_null( $install_result ) ) {
|
1364 |
+
global $wp_filesystem;
|
1365 |
+
|
1366 |
+
$error_code = 'unable_to_connect_to_filesystem';
|
1367 |
+
$error_message = $this->_fs->get_text_inline( 'Unable to connect to the filesystem. Please confirm your credentials.' );
|
1368 |
+
|
1369 |
+
// Pass through the error from WP_Filesystem if one was raised.
|
1370 |
+
if ( $wp_filesystem instanceof WP_Filesystem_Base &&
|
1371 |
+
is_wp_error( $wp_filesystem->errors ) &&
|
1372 |
+
$wp_filesystem->errors->get_error_code()
|
1373 |
+
) {
|
1374 |
+
$error_message = $wp_filesystem->errors->get_error_message();
|
1375 |
+
}
|
1376 |
+
|
1377 |
+
return array(
|
1378 |
+
'message' => $error_message,
|
1379 |
+
'code' => $error_code,
|
1380 |
+
);
|
1381 |
+
}
|
1382 |
+
|
1383 |
+
// Grab the full path to the main plugin's file.
|
1384 |
+
$plugin_activate = $upgrader->plugin_info();
|
1385 |
+
|
1386 |
+
// Try to activate the plugin.
|
1387 |
+
$activation_result = $this->try_activate_plugin( $plugin_activate );
|
1388 |
+
|
1389 |
+
if ( is_wp_error( $activation_result ) ) {
|
1390 |
+
return array(
|
1391 |
+
'message' => $activation_result->get_error_message(),
|
1392 |
+
'code' => $activation_result->get_error_code(),
|
1393 |
+
);
|
1394 |
+
}
|
1395 |
+
|
1396 |
+
return $skin->get_upgrade_messages();
|
1397 |
+
}
|
1398 |
+
|
1399 |
+
/**
|
1400 |
+
* Tries to activate a plugin. If fails, returns the error.
|
1401 |
+
*
|
1402 |
+
* @author Vova Feldman
|
1403 |
+
* @since 1.2.1.7
|
1404 |
+
*
|
1405 |
+
* @param string $file_path Path within wp-plugins/ to main plugin file.
|
1406 |
+
* This determines the styling of the output messages.
|
1407 |
+
*
|
1408 |
+
* @return bool|WP_Error
|
1409 |
+
*/
|
1410 |
+
protected function try_activate_plugin( $file_path ) {
|
1411 |
+
$activate = activate_plugin( $file_path, '', $this->_fs->is_network_active() );
|
1412 |
+
|
1413 |
+
return is_wp_error( $activate ) ?
|
1414 |
+
$activate :
|
1415 |
+
true;
|
1416 |
+
}
|
1417 |
+
|
1418 |
+
/**
|
1419 |
+
* Check if a premium module version is already active.
|
1420 |
+
*
|
1421 |
+
* @author Vova Feldman
|
1422 |
+
* @since 1.2.1.7
|
1423 |
+
*
|
1424 |
+
* @param number|bool $plugin_id
|
1425 |
+
*
|
1426 |
+
* @return bool
|
1427 |
+
*/
|
1428 |
+
private function is_premium_plugin_active( $plugin_id = false ) {
|
1429 |
+
if ( $plugin_id != $this->_fs->get_id() ) {
|
1430 |
+
return $this->_fs->is_addon_activated( $plugin_id, true );
|
1431 |
+
}
|
1432 |
+
|
1433 |
+
return is_plugin_active( $this->_fs->premium_plugin_basename() );
|
1434 |
+
}
|
1435 |
+
|
1436 |
+
/**
|
1437 |
+
* Store the basename since it's not always available in the `_maybe_adjust_source_dir` method below.
|
1438 |
+
*
|
1439 |
+
* @author Leo Fajardo (@leorw)
|
1440 |
+
* @since 2.2.1
|
1441 |
+
*
|
1442 |
+
* @param bool|WP_Error $response Response.
|
1443 |
+
* @param array $hook_extra Extra arguments passed to hooked filters.
|
1444 |
+
*
|
1445 |
+
* @return bool|WP_Error
|
1446 |
+
*/
|
1447 |
+
static function _store_basename_for_source_adjustment( $response, $hook_extra ) {
|
1448 |
+
if ( isset( $hook_extra['plugin'] ) ) {
|
1449 |
+
self::$_upgrade_basename = $hook_extra['plugin'];
|
1450 |
+
} else if ( isset( $hook_extra['theme'] ) ) {
|
1451 |
+
self::$_upgrade_basename = $hook_extra['theme'];
|
1452 |
+
} else {
|
1453 |
+
self::$_upgrade_basename = null;
|
1454 |
+
}
|
1455 |
+
|
1456 |
+
return $response;
|
1457 |
+
}
|
1458 |
+
|
1459 |
+
/**
|
1460 |
+
* Adjust the plugin directory name if necessary.
|
1461 |
+
* Assumes plugin has a folder (not a single file plugin).
|
1462 |
+
*
|
1463 |
+
* The final destination directory of a plugin is based on the subdirectory name found in the
|
1464 |
+
* (un)zipped source. In some cases this subdirectory name is not the same as the expected
|
1465 |
+
* slug and the plugin will not be recognized as installed. This is fixed by adjusting
|
1466 |
+
* the temporary unzipped source subdirectory name to the expected plugin slug.
|
1467 |
+
*
|
1468 |
+
* @author Vova Feldman
|
1469 |
+
* @since 1.2.1.7
|
1470 |
+
* @since 2.2.1 The method was converted to static since when the admin update bulk products via the Updates section, the logic applies the `upgrader_source_selection` filter for every product that is being updated.
|
1471 |
+
*
|
1472 |
+
* @param string $source Path to upgrade/zip-file-name.tmp/subdirectory/.
|
1473 |
+
* @param string $remote_source Path to upgrade/zip-file-name.tmp.
|
1474 |
+
* @param \WP_Upgrader $upgrader Instance of the upgrader which installs the plugin.
|
1475 |
+
*
|
1476 |
+
* @return string|WP_Error
|
1477 |
+
*/
|
1478 |
+
static function _maybe_adjust_source_dir( $source, $remote_source, $upgrader ) {
|
1479 |
+
if ( ! is_object( $GLOBALS['wp_filesystem'] ) ) {
|
1480 |
+
return $source;
|
1481 |
+
}
|
1482 |
+
|
1483 |
+
$basename = self::$_upgrade_basename;
|
1484 |
+
$is_theme = false;
|
1485 |
+
|
1486 |
+
// Figure out what the slug is supposed to be.
|
1487 |
+
if ( isset( $upgrader->skin->options['extra'] ) ) {
|
1488 |
+
// Set by the auto-install logic.
|
1489 |
+
$desired_slug = $upgrader->skin->options['extra']['slug'];
|
1490 |
+
} else if ( ! empty( $basename ) ) {
|
1491 |
+
/**
|
1492 |
+
* If it doesn't end with ".php", it's a theme.
|
1493 |
+
*
|
1494 |
+
* @author Leo Fajardo (@leorw)
|
1495 |
+
* @since 2.2.1
|
1496 |
+
*/
|
1497 |
+
$is_theme = ( ! fs_ends_with( $basename, '.php' ) );
|
1498 |
+
|
1499 |
+
$desired_slug = ( ! $is_theme ) ?
|
1500 |
+
dirname( $basename ) :
|
1501 |
+
// Theme slug
|
1502 |
+
$basename;
|
1503 |
+
} else {
|
1504 |
+
// Can't figure out the desired slug, stop the execution.
|
1505 |
+
return $source;
|
1506 |
+
}
|
1507 |
+
|
1508 |
+
if ( is_multisite() ) {
|
1509 |
+
/**
|
1510 |
+
* If we are running in a multisite environment and the product is not network activated,
|
1511 |
+
* the instance will not exist anyway. Therefore, try to update the source if necessary
|
1512 |
+
* regardless if the Freemius instance of the product exists or not.
|
1513 |
+
*
|
1514 |
+
* @author Vova Feldman
|
1515 |
+
*/
|
1516 |
+
} else if ( ! empty( $basename ) ) {
|
1517 |
+
$fs = Freemius::get_instance_by_file(
|
1518 |
+
$basename,
|
1519 |
+
$is_theme ?
|
1520 |
+
WP_FS__MODULE_TYPE_THEME :
|
1521 |
+
WP_FS__MODULE_TYPE_PLUGIN
|
1522 |
+
);
|
1523 |
+
|
1524 |
+
if ( ! is_object( $fs ) ) {
|
1525 |
+
/**
|
1526 |
+
* If the Freemius instance does not exist on a non-multisite network environment, it means that:
|
1527 |
+
* 1. The product is not powered by Freemius; OR
|
1528 |
+
* 2. The product is not activated, therefore, we don't mind if after the update the folder name will change.
|
1529 |
+
*
|
1530 |
+
* @author Leo Fajardo (@leorw)
|
1531 |
+
* @since 2.2.1
|
1532 |
+
*/
|
1533 |
+
return $source;
|
1534 |
+
}
|
1535 |
+
}
|
1536 |
+
|
1537 |
+
$subdir_name = untrailingslashit( str_replace( trailingslashit( $remote_source ), '', $source ) );
|
1538 |
+
|
1539 |
+
if ( ! empty( $subdir_name ) && $subdir_name !== $desired_slug ) {
|
1540 |
+
$from_path = untrailingslashit( $source );
|
1541 |
+
$to_path = trailingslashit( $remote_source ) . $desired_slug;
|
1542 |
+
|
1543 |
+
if ( true === $GLOBALS['wp_filesystem']->move( $from_path, $to_path ) ) {
|
1544 |
+
return trailingslashit( $to_path );
|
1545 |
+
}
|
1546 |
+
|
1547 |
+
return new WP_Error(
|
1548 |
+
'rename_failed',
|
1549 |
+
fs_text_inline( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.', 'module-package-rename-failure' ),
|
1550 |
+
array(
|
1551 |
+
'found' => $subdir_name,
|
1552 |
+
'expected' => $desired_slug
|
1553 |
+
)
|
1554 |
+
);
|
1555 |
+
}
|
1556 |
+
|
1557 |
+
return $source;
|
1558 |
+
}
|
1559 |
+
|
1560 |
+
#endregion
|
1561 |
+
}
|
freemius/includes/class-fs-storage.php
CHANGED
@@ -1,532 +1,532 @@
|
|
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 1.2.3
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Class FS_Storage
|
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 |
-
/**
|
24 |
-
* @var FS_Storage[]
|
25 |
-
*/
|
26 |
-
private static $_instances = array();
|
27 |
-
/**
|
28 |
-
* @var FS_Key_Value_Storage Site level storage.
|
29 |
-
*/
|
30 |
-
private $_storage;
|
31 |
-
|
32 |
-
/**
|
33 |
-
* @var FS_Key_Value_Storage Network level storage.
|
34 |
-
*/
|
35 |
-
private $_network_storage;
|
36 |
-
|
37 |
-
/**
|
38 |
-
* @var string
|
39 |
-
*/
|
40 |
-
private $_module_type;
|
41 |
-
|
42 |
-
/**
|
43 |
-
* @var string
|
44 |
-
*/
|
45 |
-
private $_module_slug;
|
46 |
-
|
47 |
-
/**
|
48 |
-
* @var int The ID of the blog that is associated with the current site level options.
|
49 |
-
*/
|
50 |
-
private $_blog_id = 0;
|
51 |
-
|
52 |
-
/**
|
53 |
-
* @var bool
|
54 |
-
*/
|
55 |
-
private $_is_multisite;
|
56 |
-
|
57 |
-
/**
|
58 |
-
* @var bool
|
59 |
-
*/
|
60 |
-
private $_is_network_active = false;
|
61 |
-
|
62 |
-
/**
|
63 |
-
* @var bool
|
64 |
-
*/
|
65 |
-
private $_is_delegated_connection = false;
|
66 |
-
|
67 |
-
/**
|
68 |
-
* @var array {
|
69 |
-
* @key string Option name.
|
70 |
-
* @value int If 0 store on the network level. If 1, store on the network level only if module was network level activated. If 2, store on the network level only if network activated and NOT delegated the connection.
|
71 |
-
* }
|
72 |
-
*/
|
73 |
-
private static $_NETWORK_OPTIONS_MAP;
|
74 |
-
|
75 |
-
/**
|
76 |
-
* @author Leo Fajardo (@leorw)
|
77 |
-
*
|
78 |
-
* @param string $module_type
|
79 |
-
* @param string $slug
|
80 |
-
*
|
81 |
-
* @return FS_Storage
|
82 |
-
*/
|
83 |
-
static function instance( $module_type, $slug ) {
|
84 |
-
$key = $module_type . ':' . $slug;
|
85 |
-
|
86 |
-
if ( ! isset( self::$_instances[ $key ] ) ) {
|
87 |
-
self::$_instances[ $key ] = new FS_Storage( $module_type, $slug );
|
88 |
-
}
|
89 |
-
|
90 |
-
return self::$_instances[ $key ];
|
91 |
-
}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* @author Leo Fajardo (@leorw)
|
95 |
-
*
|
96 |
-
* @param string $module_type
|
97 |
-
* @param string $slug
|
98 |
-
*/
|
99 |
-
private function __construct( $module_type, $slug ) {
|
100 |
-
$this->_module_type = $module_type;
|
101 |
-
$this->_module_slug = $slug;
|
102 |
-
$this->_is_multisite = is_multisite();
|
103 |
-
|
104 |
-
if ( $this->_is_multisite ) {
|
105 |
-
$this->_blog_id = get_current_blog_id();
|
106 |
-
$this->_network_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, true );
|
107 |
-
}
|
108 |
-
|
109 |
-
$this->_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, $this->_blog_id );
|
110 |
-
}
|
111 |
-
|
112 |
-
/**
|
113 |
-
* Tells this storage wrapper class that the context plugin is network active. This flag will affect how values
|
114 |
-
* are retrieved/stored from/into the storage.
|
115 |
-
*
|
116 |
-
* @author Leo Fajardo (@leorw)
|
117 |
-
*
|
118 |
-
* @param bool $is_network_active
|
119 |
-
* @param bool $is_delegated_connection
|
120 |
-
*/
|
121 |
-
function set_network_active( $is_network_active = true, $is_delegated_connection = false ) {
|
122 |
-
$this->_is_network_active = $is_network_active;
|
123 |
-
$this->_is_delegated_connection = $is_delegated_connection;
|
124 |
-
}
|
125 |
-
|
126 |
-
/**
|
127 |
-
* Switch the context of the site level storage manager.
|
128 |
-
*
|
129 |
-
* @author Vova Feldman (@svovaf)
|
130 |
-
* @since 2.0.0
|
131 |
-
*
|
132 |
-
* @param int $blog_id
|
133 |
-
*/
|
134 |
-
function set_site_blog_context( $blog_id ) {
|
135 |
-
$this->_storage = $this->get_site_storage( $blog_id );
|
136 |
-
$this->_blog_id = $blog_id;
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* @author Leo Fajardo (@leorw)
|
141 |
-
*
|
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 );
|
152 |
-
$storage->store( $key, $value, $flush );
|
153 |
-
}
|
154 |
-
}
|
155 |
-
|
156 |
-
/**
|
157 |
-
* @author Leo Fajardo (@leorw)
|
158 |
-
*
|
159 |
-
* @param bool $store
|
160 |
-
* @param string[] $exceptions Set of keys to keep and not clear.
|
161 |
-
* @param int|null|bool $network_level_or_blog_id
|
162 |
-
*/
|
163 |
-
function clear_all( $store = true, $exceptions = array(), $network_level_or_blog_id = null ) {
|
164 |
-
if ( ! $this->_is_multisite ||
|
165 |
-
false === $network_level_or_blog_id ||
|
166 |
-
is_null( $network_level_or_blog_id ) ||
|
167 |
-
is_numeric( $network_level_or_blog_id )
|
168 |
-
) {
|
169 |
-
$storage = $this->get_site_storage( $network_level_or_blog_id );
|
170 |
-
$storage->clear_all( $store, $exceptions );
|
171 |
-
}
|
172 |
-
|
173 |
-
if ( $this->_is_multisite &&
|
174 |
-
( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
|
175 |
-
) {
|
176 |
-
$this->_network_storage->clear_all( $store, $exceptions );
|
177 |
-
}
|
178 |
-
}
|
179 |
-
|
180 |
-
/**
|
181 |
-
* @author Leo Fajardo (@leorw)
|
182 |
-
*
|
183 |
-
* @param string $key
|
184 |
-
* @param bool $store
|
185 |
-
* @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).
|
186 |
-
*/
|
187 |
-
function remove( $key, $store = true, $network_level_or_blog_id = null ) {
|
188 |
-
if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
|
189 |
-
$this->_network_storage->remove( $key, $store );
|
190 |
-
} else {
|
191 |
-
$storage = $this->get_site_storage( $network_level_or_blog_id );
|
192 |
-
$storage->remove( $key, $store );
|
193 |
-
}
|
194 |
-
}
|
195 |
-
|
196 |
-
/**
|
197 |
-
* @author Leo Fajardo (@leorw)
|
198 |
-
*
|
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 );
|
210 |
-
|
211 |
-
return $storage->get( $key, $default );
|
212 |
-
}
|
213 |
-
}
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Multisite activated:
|
217 |
-
* true: Save network storage.
|
218 |
-
* int: Save site specific storage.
|
219 |
-
* false|0: Save current site storage.
|
220 |
-
* null: Save network and current site storage.
|
221 |
-
* Site level activated:
|
222 |
-
* Save site storage.
|
223 |
-
*
|
224 |
-
* @author Vova Feldman (@svovaf)
|
225 |
-
* @since 2.0.0
|
226 |
-
*
|
227 |
-
* @param bool|int|null $network_level_or_blog_id
|
228 |
-
*/
|
229 |
-
function save( $network_level_or_blog_id = null ) {
|
230 |
-
if ( $this->_is_network_active &&
|
231 |
-
( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
|
232 |
-
) {
|
233 |
-
$this->_network_storage->save();
|
234 |
-
}
|
235 |
-
|
236 |
-
if ( ! $this->_is_network_active || true !== $network_level_or_blog_id ) {
|
237 |
-
$storage = $this->get_site_storage( $network_level_or_blog_id );
|
238 |
-
$storage->save();
|
239 |
-
}
|
240 |
-
}
|
241 |
-
|
242 |
-
/**
|
243 |
-
* @author Vova Feldman (@svovaf)
|
244 |
-
* @since 2.0.0
|
245 |
-
*
|
246 |
-
* @return string
|
247 |
-
*/
|
248 |
-
function get_module_slug() {
|
249 |
-
return $this->_module_slug;
|
250 |
-
}
|
251 |
-
|
252 |
-
/**
|
253 |
-
* @author Vova Feldman (@svovaf)
|
254 |
-
* @since 2.0.0
|
255 |
-
*
|
256 |
-
* @return string
|
257 |
-
*/
|
258 |
-
function get_module_type() {
|
259 |
-
return $this->_module_type;
|
260 |
-
}
|
261 |
-
|
262 |
-
/**
|
263 |
-
* Migration script to the new storage data structure that is network compatible.
|
264 |
-
*
|
265 |
-
* IMPORTANT:
|
266 |
-
* This method should be executed only after it is determined if this is a network
|
267 |
-
* level compatible product activation.
|
268 |
-
*
|
269 |
-
* @author Vova Feldman (@svovaf)
|
270 |
-
* @since 2.0.0
|
271 |
-
*/
|
272 |
-
function migrate_to_network() {
|
273 |
-
if ( ! $this->_is_multisite ) {
|
274 |
-
return;
|
275 |
-
}
|
276 |
-
|
277 |
-
$updated = false;
|
278 |
-
|
279 |
-
if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
|
280 |
-
self::load_network_options_map();
|
281 |
-
}
|
282 |
-
|
283 |
-
foreach ( self::$_NETWORK_OPTIONS_MAP as $option => $storage_level ) {
|
284 |
-
if ( ! $this->is_multisite_option( $option ) ) {
|
285 |
-
continue;
|
286 |
-
}
|
287 |
-
|
288 |
-
if ( isset( $this->_storage->{$option} ) && ! isset( $this->_network_storage->{$option} ) ) {
|
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 |
-
}
|
308 |
-
|
309 |
-
if ( ! $updated ) {
|
310 |
-
return;
|
311 |
-
}
|
312 |
-
|
313 |
-
// Update network level storage.
|
314 |
-
$this->_network_storage->save();
|
315 |
-
// $this->_storage->save();
|
316 |
-
}
|
317 |
-
|
318 |
-
#--------------------------------------------------------------------------------
|
319 |
-
#region Helper Methods
|
320 |
-
#--------------------------------------------------------------------------------
|
321 |
-
|
322 |
-
/**
|
323 |
-
* We don't want to load the map right away since it's not even needed in a non-MS environment.
|
324 |
-
*
|
325 |
-
* Example:
|
326 |
-
* array(
|
327 |
-
* 'option1' => 0, // Means that the option should always be stored on the network level.
|
328 |
-
* 'option2' => 1, // Means that the option should be stored on the network level only when the module was network level activated.
|
329 |
-
* 'option2' => 2, // Means that the option should be stored on the network level only when the module was network level activated AND the connection was NOT delegated.
|
330 |
-
* 'option3' => 3, // Means that the option should always be stored on the site level.
|
331 |
-
* )
|
332 |
-
*
|
333 |
-
* @author Vova Feldman (@svovaf)
|
334 |
-
* @since 2.0.0
|
335 |
-
*/
|
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 |
-
|
399 |
-
/**
|
400 |
-
* This method will and should only be executed when is_multisite() is true.
|
401 |
-
*
|
402 |
-
* @author Vova Feldman (@svovaf)
|
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 |
-
}
|
428 |
-
|
429 |
-
if ( ! $this->_is_network_active ) {
|
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 |
-
}
|
442 |
-
|
443 |
-
return false;
|
444 |
-
}
|
445 |
-
|
446 |
-
/**
|
447 |
-
* @author Leo Fajardo
|
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;
|
458 |
-
}
|
459 |
-
|
460 |
-
if ( is_numeric( $network_level_or_blog_id ) ) {
|
461 |
-
// Explicitly asked to use a specified blog storage.
|
462 |
-
return false;
|
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 |
-
/**
|
475 |
-
* @author Vova Feldman (@svovaf)
|
476 |
-
* @since 2.0.0
|
477 |
-
*
|
478 |
-
* @param int $blog_id
|
479 |
-
*
|
480 |
-
* @return \FS_Key_Value_Storage
|
481 |
-
*/
|
482 |
-
private function get_site_storage( $blog_id = 0 ) {
|
483 |
-
if ( ! is_numeric( $blog_id ) ||
|
484 |
-
$blog_id == $this->_blog_id ||
|
485 |
-
0 == $blog_id
|
486 |
-
) {
|
487 |
-
return $this->_storage;
|
488 |
-
}
|
489 |
-
|
490 |
-
return FS_Key_Value_Storage::instance(
|
491 |
-
$this->_module_type . '_data',
|
492 |
-
$this->_storage->get_secondary_id(),
|
493 |
-
$blog_id
|
494 |
-
);
|
495 |
-
}
|
496 |
-
|
497 |
-
#endregion
|
498 |
-
|
499 |
-
#--------------------------------------------------------------------------------
|
500 |
-
#region Magic methods
|
501 |
-
#--------------------------------------------------------------------------------
|
502 |
-
|
503 |
-
function __set( $k, $v ) {
|
504 |
-
if ( $this->should_use_network_storage( $k ) ) {
|
505 |
-
$this->_network_storage->{$k} = $v;
|
506 |
-
} else {
|
507 |
-
$this->_storage->{$k} = $v;
|
508 |
-
}
|
509 |
-
}
|
510 |
-
|
511 |
-
function __isset( $k ) {
|
512 |
-
return $this->should_use_network_storage( $k ) ?
|
513 |
-
isset( $this->_network_storage->{$k} ) :
|
514 |
-
isset( $this->_storage->{$k} );
|
515 |
-
}
|
516 |
-
|
517 |
-
function __unset( $k ) {
|
518 |
-
if ( $this->should_use_network_storage( $k ) ) {
|
519 |
-
unset( $this->_network_storage->{$k} );
|
520 |
-
} else {
|
521 |
-
unset( $this->_storage->{$k} );
|
522 |
-
}
|
523 |
-
}
|
524 |
-
|
525 |
-
function __get( $k ) {
|
526 |
-
return $this->should_use_network_storage( $k ) ?
|
527 |
-
$this->_network_storage->{$k} :
|
528 |
-
$this->_storage->{$k};
|
529 |
-
}
|
530 |
-
|
531 |
-
#endregion
|
532 |
}
|
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 1.2.3
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Class FS_Storage
|
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 |
+
/**
|
24 |
+
* @var FS_Storage[]
|
25 |
+
*/
|
26 |
+
private static $_instances = array();
|
27 |
+
/**
|
28 |
+
* @var FS_Key_Value_Storage Site level storage.
|
29 |
+
*/
|
30 |
+
private $_storage;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @var FS_Key_Value_Storage Network level storage.
|
34 |
+
*/
|
35 |
+
private $_network_storage;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @var string
|
39 |
+
*/
|
40 |
+
private $_module_type;
|
41 |
+
|
42 |
+
/**
|
43 |
+
* @var string
|
44 |
+
*/
|
45 |
+
private $_module_slug;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @var int The ID of the blog that is associated with the current site level options.
|
49 |
+
*/
|
50 |
+
private $_blog_id = 0;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* @var bool
|
54 |
+
*/
|
55 |
+
private $_is_multisite;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* @var bool
|
59 |
+
*/
|
60 |
+
private $_is_network_active = false;
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @var bool
|
64 |
+
*/
|
65 |
+
private $_is_delegated_connection = false;
|
66 |
+
|
67 |
+
/**
|
68 |
+
* @var array {
|
69 |
+
* @key string Option name.
|
70 |
+
* @value int If 0 store on the network level. If 1, store on the network level only if module was network level activated. If 2, store on the network level only if network activated and NOT delegated the connection.
|
71 |
+
* }
|
72 |
+
*/
|
73 |
+
private static $_NETWORK_OPTIONS_MAP;
|
74 |
+
|
75 |
+
/**
|
76 |
+
* @author Leo Fajardo (@leorw)
|
77 |
+
*
|
78 |
+
* @param string $module_type
|
79 |
+
* @param string $slug
|
80 |
+
*
|
81 |
+
* @return FS_Storage
|
82 |
+
*/
|
83 |
+
static function instance( $module_type, $slug ) {
|
84 |
+
$key = $module_type . ':' . $slug;
|
85 |
+
|
86 |
+
if ( ! isset( self::$_instances[ $key ] ) ) {
|
87 |
+
self::$_instances[ $key ] = new FS_Storage( $module_type, $slug );
|
88 |
+
}
|
89 |
+
|
90 |
+
return self::$_instances[ $key ];
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @author Leo Fajardo (@leorw)
|
95 |
+
*
|
96 |
+
* @param string $module_type
|
97 |
+
* @param string $slug
|
98 |
+
*/
|
99 |
+
private function __construct( $module_type, $slug ) {
|
100 |
+
$this->_module_type = $module_type;
|
101 |
+
$this->_module_slug = $slug;
|
102 |
+
$this->_is_multisite = is_multisite();
|
103 |
+
|
104 |
+
if ( $this->_is_multisite ) {
|
105 |
+
$this->_blog_id = get_current_blog_id();
|
106 |
+
$this->_network_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, true );
|
107 |
+
}
|
108 |
+
|
109 |
+
$this->_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, $this->_blog_id );
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Tells this storage wrapper class that the context plugin is network active. This flag will affect how values
|
114 |
+
* are retrieved/stored from/into the storage.
|
115 |
+
*
|
116 |
+
* @author Leo Fajardo (@leorw)
|
117 |
+
*
|
118 |
+
* @param bool $is_network_active
|
119 |
+
* @param bool $is_delegated_connection
|
120 |
+
*/
|
121 |
+
function set_network_active( $is_network_active = true, $is_delegated_connection = false ) {
|
122 |
+
$this->_is_network_active = $is_network_active;
|
123 |
+
$this->_is_delegated_connection = $is_delegated_connection;
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Switch the context of the site level storage manager.
|
128 |
+
*
|
129 |
+
* @author Vova Feldman (@svovaf)
|
130 |
+
* @since 2.0.0
|
131 |
+
*
|
132 |
+
* @param int $blog_id
|
133 |
+
*/
|
134 |
+
function set_site_blog_context( $blog_id ) {
|
135 |
+
$this->_storage = $this->get_site_storage( $blog_id );
|
136 |
+
$this->_blog_id = $blog_id;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* @author Leo Fajardo (@leorw)
|
141 |
+
*
|
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 );
|
152 |
+
$storage->store( $key, $value, $flush );
|
153 |
+
}
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* @author Leo Fajardo (@leorw)
|
158 |
+
*
|
159 |
+
* @param bool $store
|
160 |
+
* @param string[] $exceptions Set of keys to keep and not clear.
|
161 |
+
* @param int|null|bool $network_level_or_blog_id
|
162 |
+
*/
|
163 |
+
function clear_all( $store = true, $exceptions = array(), $network_level_or_blog_id = null ) {
|
164 |
+
if ( ! $this->_is_multisite ||
|
165 |
+
false === $network_level_or_blog_id ||
|
166 |
+
is_null( $network_level_or_blog_id ) ||
|
167 |
+
is_numeric( $network_level_or_blog_id )
|
168 |
+
) {
|
169 |
+
$storage = $this->get_site_storage( $network_level_or_blog_id );
|
170 |
+
$storage->clear_all( $store, $exceptions );
|
171 |
+
}
|
172 |
+
|
173 |
+
if ( $this->_is_multisite &&
|
174 |
+
( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
|
175 |
+
) {
|
176 |
+
$this->_network_storage->clear_all( $store, $exceptions );
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* @author Leo Fajardo (@leorw)
|
182 |
+
*
|
183 |
+
* @param string $key
|
184 |
+
* @param bool $store
|
185 |
+
* @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).
|
186 |
+
*/
|
187 |
+
function remove( $key, $store = true, $network_level_or_blog_id = null ) {
|
188 |
+
if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
|
189 |
+
$this->_network_storage->remove( $key, $store );
|
190 |
+
} else {
|
191 |
+
$storage = $this->get_site_storage( $network_level_or_blog_id );
|
192 |
+
$storage->remove( $key, $store );
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
/**
|
197 |
+
* @author Leo Fajardo (@leorw)
|
198 |
+
*
|
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 );
|
210 |
+
|
211 |
+
return $storage->get( $key, $default );
|
212 |
+
}
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Multisite activated:
|
217 |
+
* true: Save network storage.
|
218 |
+
* int: Save site specific storage.
|
219 |
+
* false|0: Save current site storage.
|
220 |
+
* null: Save network and current site storage.
|
221 |
+
* Site level activated:
|
222 |
+
* Save site storage.
|
223 |
+
*
|
224 |
+
* @author Vova Feldman (@svovaf)
|
225 |
+
* @since 2.0.0
|
226 |
+
*
|
227 |
+
* @param bool|int|null $network_level_or_blog_id
|
228 |
+
*/
|
229 |
+
function save( $network_level_or_blog_id = null ) {
|
230 |
+
if ( $this->_is_network_active &&
|
231 |
+
( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
|
232 |
+
) {
|
233 |
+
$this->_network_storage->save();
|
234 |
+
}
|
235 |
+
|
236 |
+
if ( ! $this->_is_network_active || true !== $network_level_or_blog_id ) {
|
237 |
+
$storage = $this->get_site_storage( $network_level_or_blog_id );
|
238 |
+
$storage->save();
|
239 |
+
}
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* @author Vova Feldman (@svovaf)
|
244 |
+
* @since 2.0.0
|
245 |
+
*
|
246 |
+
* @return string
|
247 |
+
*/
|
248 |
+
function get_module_slug() {
|
249 |
+
return $this->_module_slug;
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* @author Vova Feldman (@svovaf)
|
254 |
+
* @since 2.0.0
|
255 |
+
*
|
256 |
+
* @return string
|
257 |
+
*/
|
258 |
+
function get_module_type() {
|
259 |
+
return $this->_module_type;
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Migration script to the new storage data structure that is network compatible.
|
264 |
+
*
|
265 |
+
* IMPORTANT:
|
266 |
+
* This method should be executed only after it is determined if this is a network
|
267 |
+
* level compatible product activation.
|
268 |
+
*
|
269 |
+
* @author Vova Feldman (@svovaf)
|
270 |
+
* @since 2.0.0
|
271 |
+
*/
|
272 |
+
function migrate_to_network() {
|
273 |
+
if ( ! $this->_is_multisite ) {
|
274 |
+
return;
|
275 |
+
}
|
276 |
+
|
277 |
+
$updated = false;
|
278 |
+
|
279 |
+
if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
|
280 |
+
self::load_network_options_map();
|
281 |
+
}
|
282 |
+
|
283 |
+
foreach ( self::$_NETWORK_OPTIONS_MAP as $option => $storage_level ) {
|
284 |
+
if ( ! $this->is_multisite_option( $option ) ) {
|
285 |
+
continue;
|
286 |
+
}
|
287 |
+
|
288 |
+
if ( isset( $this->_storage->{$option} ) && ! isset( $this->_network_storage->{$option} ) ) {
|
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 |
+
}
|
308 |
+
|
309 |
+
if ( ! $updated ) {
|
310 |
+
return;
|
311 |
+
}
|
312 |
+
|
313 |
+
// Update network level storage.
|
314 |
+
$this->_network_storage->save();
|
315 |
+
// $this->_storage->save();
|
316 |
+
}
|
317 |
+
|
318 |
+
#--------------------------------------------------------------------------------
|
319 |
+
#region Helper Methods
|
320 |
+
#--------------------------------------------------------------------------------
|
321 |
+
|
322 |
+
/**
|
323 |
+
* We don't want to load the map right away since it's not even needed in a non-MS environment.
|
324 |
+
*
|
325 |
+
* Example:
|
326 |
+
* array(
|
327 |
+
* 'option1' => 0, // Means that the option should always be stored on the network level.
|
328 |
+
* 'option2' => 1, // Means that the option should be stored on the network level only when the module was network level activated.
|
329 |
+
* 'option2' => 2, // Means that the option should be stored on the network level only when the module was network level activated AND the connection was NOT delegated.
|
330 |
+
* 'option3' => 3, // Means that the option should always be stored on the site level.
|
331 |
+
* )
|
332 |
+
*
|
333 |
+
* @author Vova Feldman (@svovaf)
|
334 |
+
* @since 2.0.0
|
335 |
+
*/
|
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 |
+
|
399 |
+
/**
|
400 |
+
* This method will and should only be executed when is_multisite() is true.
|
401 |
+
*
|
402 |
+
* @author Vova Feldman (@svovaf)
|
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 |
+
}
|
428 |
+
|
429 |
+
if ( ! $this->_is_network_active ) {
|
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 |
+
}
|
442 |
+
|
443 |
+
return false;
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* @author Leo Fajardo
|
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;
|
458 |
+
}
|
459 |
+
|
460 |
+
if ( is_numeric( $network_level_or_blog_id ) ) {
|
461 |
+
// Explicitly asked to use a specified blog storage.
|
462 |
+
return false;
|
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 |
+
/**
|
475 |
+
* @author Vova Feldman (@svovaf)
|
476 |
+
* @since 2.0.0
|
477 |
+
*
|
478 |
+
* @param int $blog_id
|
479 |
+
*
|
480 |
+
* @return \FS_Key_Value_Storage
|
481 |
+
*/
|
482 |
+
private function get_site_storage( $blog_id = 0 ) {
|
483 |
+
if ( ! is_numeric( $blog_id ) ||
|
484 |
+
$blog_id == $this->_blog_id ||
|
485 |
+
0 == $blog_id
|
486 |
+
) {
|
487 |
+
return $this->_storage;
|
488 |
+
}
|
489 |
+
|
490 |
+
return FS_Key_Value_Storage::instance(
|
491 |
+
$this->_module_type . '_data',
|
492 |
+
$this->_storage->get_secondary_id(),
|
493 |
+
$blog_id
|
494 |
+
);
|
495 |
+
}
|
496 |
+
|
497 |
+
#endregion
|
498 |
+
|
499 |
+
#--------------------------------------------------------------------------------
|
500 |
+
#region Magic methods
|
501 |
+
#--------------------------------------------------------------------------------
|
502 |
+
|
503 |
+
function __set( $k, $v ) {
|
504 |
+
if ( $this->should_use_network_storage( $k ) ) {
|
505 |
+
$this->_network_storage->{$k} = $v;
|
506 |
+
} else {
|
507 |
+
$this->_storage->{$k} = $v;
|
508 |
+
}
|
509 |
+
}
|
510 |
+
|
511 |
+
function __isset( $k ) {
|
512 |
+
return $this->should_use_network_storage( $k ) ?
|
513 |
+
isset( $this->_network_storage->{$k} ) :
|
514 |
+
isset( $this->_storage->{$k} );
|
515 |
+
}
|
516 |
+
|
517 |
+
function __unset( $k ) {
|
518 |
+
if ( $this->should_use_network_storage( $k ) ) {
|
519 |
+
unset( $this->_network_storage->{$k} );
|
520 |
+
} else {
|
521 |
+
unset( $this->_storage->{$k} );
|
522 |
+
}
|
523 |
+
}
|
524 |
+
|
525 |
+
function __get( $k ) {
|
526 |
+
return $this->should_use_network_storage( $k ) ?
|
527 |
+
$this->_network_storage->{$k} :
|
528 |
+
$this->_storage->{$k};
|
529 |
+
}
|
530 |
+
|
531 |
+
#endregion
|
532 |
}
|
freemius/includes/fs-core-functions.php
CHANGED
@@ -1,1416 +1,1416 @@
|
|
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 1.0.3
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
if ( ! function_exists( 'fs_dummy' ) ) {
|
14 |
-
function fs_dummy() {
|
15 |
-
}
|
16 |
-
}
|
17 |
-
|
18 |
-
/* Url.
|
19 |
-
--------------------------------------------------------------------------------------------*/
|
20 |
-
if ( ! function_exists( 'fs_get_url_daily_cache_killer' ) ) {
|
21 |
-
function fs_get_url_daily_cache_killer() {
|
22 |
-
return date( '\YY\Mm\Dd' );
|
23 |
-
}
|
24 |
-
}
|
25 |
-
|
26 |
-
/* Templates / Views.
|
27 |
-
--------------------------------------------------------------------------------------------*/
|
28 |
-
if ( ! function_exists( 'fs_get_template_path' ) ) {
|
29 |
-
function fs_get_template_path( $path ) {
|
30 |
-
return WP_FS__DIR_TEMPLATES . '/' . trim( $path, '/' );
|
31 |
-
}
|
32 |
-
|
33 |
-
function fs_include_template( $path, &$params = null ) {
|
34 |
-
$VARS = &$params;
|
35 |
-
include fs_get_template_path( $path );
|
36 |
-
}
|
37 |
-
|
38 |
-
function fs_include_once_template( $path, &$params = null ) {
|
39 |
-
$VARS = &$params;
|
40 |
-
include_once fs_get_template_path( $path );
|
41 |
-
}
|
42 |
-
|
43 |
-
function fs_require_template( $path, &$params = null ) {
|
44 |
-
$VARS = &$params;
|
45 |
-
require fs_get_template_path( $path );
|
46 |
-
}
|
47 |
-
|
48 |
-
function fs_require_once_template( $path, &$params = null ) {
|
49 |
-
$VARS = &$params;
|
50 |
-
require_once fs_get_template_path( $path );
|
51 |
-
}
|
52 |
-
|
53 |
-
function fs_get_template( $path, &$params = null ) {
|
54 |
-
ob_start();
|
55 |
-
|
56 |
-
$VARS = &$params;
|
57 |
-
require fs_get_template_path( $path );
|
58 |
-
|
59 |
-
return ob_get_clean();
|
60 |
-
}
|
61 |
-
}
|
62 |
-
|
63 |
-
/* Scripts and styles including.
|
64 |
-
--------------------------------------------------------------------------------------------*/
|
65 |
-
|
66 |
-
if ( ! function_exists( 'fs_asset_url' ) ) {
|
67 |
-
/**
|
68 |
-
* Generates an absolute URL to the given path. This function ensures that the URL will be correct whether the asset
|
69 |
-
* is inside a plugin's folder or a theme's folder.
|
70 |
-
*
|
71 |
-
* Examples:
|
72 |
-
* 1. "themes" folder
|
73 |
-
* Path: C:/xampp/htdocs/fswp/wp-content/themes/twentytwelve/freemius/assets/css/admin/common.css
|
74 |
-
* URL: http://fswp:8080/wp-content/themes/twentytwelve/freemius/assets/css/admin/common.css
|
75 |
-
*
|
76 |
-
* 2. "plugins" folder
|
77 |
-
* Path: C:/xampp/htdocs/fswp/wp-content/plugins/rating-widget-premium/freemius/assets/css/admin/common.css
|
78 |
-
* URL: http://fswp:8080/wp-content/plugins/rating-widget-premium/freemius/assets/css/admin/common.css
|
79 |
-
*
|
80 |
-
* @author Leo Fajardo (@leorw)
|
81 |
-
* @since 1.2.2
|
82 |
-
*
|
83 |
-
* @param string $asset_abs_path Asset's absolute path.
|
84 |
-
*
|
85 |
-
* @return string Asset's URL.
|
86 |
-
*/
|
87 |
-
function fs_asset_url( $asset_abs_path ) {
|
88 |
-
$wp_content_dir = fs_normalize_path( WP_CONTENT_DIR );
|
89 |
-
$asset_abs_path = fs_normalize_path( $asset_abs_path );
|
90 |
-
|
91 |
-
if ( 0 === strpos( $asset_abs_path, $wp_content_dir ) ) {
|
92 |
-
// Handle both theme and plugin assets located in the standard directories.
|
93 |
-
$asset_rel_path = str_replace( $wp_content_dir, '', $asset_abs_path );
|
94 |
-
$asset_url = content_url( fs_normalize_path( $asset_rel_path ) );
|
95 |
-
} else {
|
96 |
-
$wp_plugins_dir = fs_normalize_path( WP_PLUGIN_DIR );
|
97 |
-
if ( 0 === strpos( $asset_abs_path, $wp_plugins_dir ) ) {
|
98 |
-
// Try to handle plugin assets that may be located in a non-standard plugins directory.
|
99 |
-
$asset_rel_path = str_replace( $wp_plugins_dir, '', $asset_abs_path );
|
100 |
-
$asset_url = plugins_url( fs_normalize_path( $asset_rel_path ) );
|
101 |
-
} else {
|
102 |
-
// Try to handle theme assets that may be located in a non-standard themes directory.
|
103 |
-
$active_theme_stylesheet = get_stylesheet();
|
104 |
-
$wp_themes_dir = fs_normalize_path( trailingslashit( get_theme_root( $active_theme_stylesheet ) ) );
|
105 |
-
$asset_rel_path = str_replace( $wp_themes_dir, '', fs_normalize_path( $asset_abs_path ) );
|
106 |
-
$asset_url = trailingslashit( get_theme_root_uri( $active_theme_stylesheet ) ) . fs_normalize_path( $asset_rel_path );
|
107 |
-
}
|
108 |
-
}
|
109 |
-
|
110 |
-
return $asset_url;
|
111 |
-
}
|
112 |
-
}
|
113 |
-
|
114 |
-
if ( ! function_exists( 'fs_enqueue_local_style' ) ) {
|
115 |
-
function fs_enqueue_local_style( $handle, $path, $deps = array(), $ver = false, $media = 'all' ) {
|
116 |
-
wp_enqueue_style( $handle, fs_asset_url( WP_FS__DIR_CSS . '/' . trim( $path, '/' ) ), $deps, $ver, $media );
|
117 |
-
}
|
118 |
-
}
|
119 |
-
|
120 |
-
if ( ! function_exists( 'fs_enqueue_local_script' ) ) {
|
121 |
-
function fs_enqueue_local_script( $handle, $path, $deps = array(), $ver = false, $in_footer = 'all' ) {
|
122 |
-
wp_enqueue_script( $handle, fs_asset_url( WP_FS__DIR_JS . '/' . trim( $path, '/' ) ), $deps, $ver, $in_footer );
|
123 |
-
}
|
124 |
-
}
|
125 |
-
|
126 |
-
if ( ! function_exists( 'fs_img_url' ) ) {
|
127 |
-
function fs_img_url( $path, $img_dir = WP_FS__DIR_IMG ) {
|
128 |
-
return ( fs_asset_url( $img_dir . '/' . trim( $path, '/' ) ) );
|
129 |
-
}
|
130 |
-
}
|
131 |
-
|
132 |
-
#--------------------------------------------------------------------------------
|
133 |
-
#region Request handlers.
|
134 |
-
#--------------------------------------------------------------------------------
|
135 |
-
|
136 |
-
if ( ! function_exists( 'fs_request_get' ) ) {
|
137 |
-
/**
|
138 |
-
* A helper method to fetch GET/POST user input with an optional default value when the input is not set.
|
139 |
-
* @author Vova Feldman (@svovaf)
|
140 |
-
*
|
141 |
-
* @param string $key
|
142 |
-
* @param mixed $def
|
143 |
-
* @param string|bool $type Since 1.2.1.7 - when set to 'get' will look for the value passed via querystring, when
|
144 |
-
* set to 'post' will look for the value passed via the POST request's body, otherwise,
|
145 |
-
* will check if the parameter was passed in any of the two.
|
146 |
-
*
|
147 |
-
* @return mixed
|
148 |
-
*/
|
149 |
-
function fs_request_get( $key, $def = false, $type = false ) {
|
150 |
-
if ( is_string( $type ) ) {
|
151 |
-
$type = strtolower( $type );
|
152 |
-
}
|
153 |
-
|
154 |
-
/**
|
155 |
-
* Note to WordPress.org Reviewers:
|
156 |
-
* This is a helper method to fetch GET/POST user input with an optional default value when the input is not set. The actual sanitization is done in the scope of the function's usage.
|
157 |
-
*/
|
158 |
-
switch ( $type ) {
|
159 |
-
case 'post':
|
160 |
-
$value = isset( $_POST[ $key ] ) ? $_POST[ $key ] : $def;
|
161 |
-
break;
|
162 |
-
case 'get':
|
163 |
-
$value = isset( $_GET[ $key ] ) ? $_GET[ $key ] : $def;
|
164 |
-
break;
|
165 |
-
default:
|
166 |
-
$value = isset( $_REQUEST[ $key ] ) ? $_REQUEST[ $key ] : $def;
|
167 |
-
break;
|
168 |
-
}
|
169 |
-
|
170 |
-
return $value;
|
171 |
-
}
|
172 |
-
}
|
173 |
-
|
174 |
-
if ( ! function_exists( 'fs_request_has' ) ) {
|
175 |
-
function fs_request_has( $key ) {
|
176 |
-
return isset( $_REQUEST[ $key ] );
|
177 |
-
}
|
178 |
-
}
|
179 |
-
|
180 |
-
if ( ! function_exists( 'fs_request_get_bool' ) ) {
|
181 |
-
/**
|
182 |
-
* A helper method to fetch GET/POST user boolean input with an optional default value when the input is not set.
|
183 |
-
*
|
184 |
-
* @author Vova Feldman (@svovaf)
|
185 |
-
*
|
186 |
-
* @param string $key
|
187 |
-
* @param bool $def
|
188 |
-
*
|
189 |
-
* @return bool|mixed
|
190 |
-
*/
|
191 |
-
function fs_request_get_bool( $key, $def = false ) {
|
192 |
-
$val = fs_request_get( $key, null );
|
193 |
-
|
194 |
-
if ( is_null( $val ) ) {
|
195 |
-
return $def;
|
196 |
-
}
|
197 |
-
|
198 |
-
if ( is_bool( $val ) ) {
|
199 |
-
return $val;
|
200 |
-
} else if ( is_numeric( $val ) ) {
|
201 |
-
if ( 1 == $val ) {
|
202 |
-
return true;
|
203 |
-
} else if ( 0 == $val ) {
|
204 |
-
return false;
|
205 |
-
}
|
206 |
-
} else if ( is_string( $val ) ) {
|
207 |
-
$val = strtolower( $val );
|
208 |
-
|
209 |
-
if ( 'true' === $val ) {
|
210 |
-
return true;
|
211 |
-
} else if ( 'false' === $val ) {
|
212 |
-
return false;
|
213 |
-
}
|
214 |
-
}
|
215 |
-
|
216 |
-
return $def;
|
217 |
-
}
|
218 |
-
}
|
219 |
-
|
220 |
-
if ( ! function_exists( 'fs_request_is_post' ) ) {
|
221 |
-
function fs_request_is_post() {
|
222 |
-
return ( 'post' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
|
223 |
-
}
|
224 |
-
}
|
225 |
-
|
226 |
-
if ( ! function_exists( 'fs_request_is_get' ) ) {
|
227 |
-
function fs_request_is_get() {
|
228 |
-
return ( 'get' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
|
229 |
-
}
|
230 |
-
}
|
231 |
-
|
232 |
-
if ( ! function_exists( 'fs_get_action' ) ) {
|
233 |
-
function fs_get_action( $action_key = 'action' ) {
|
234 |
-
if ( ! empty( $_REQUEST[ $action_key ] ) && is_string( $_REQUEST[ $action_key ] ) ) {
|
235 |
-
return strtolower( $_REQUEST[ $action_key ] );
|
236 |
-
}
|
237 |
-
|
238 |
-
if ( 'action' == $action_key ) {
|
239 |
-
$action_key = 'fs_action';
|
240 |
-
|
241 |
-
if ( ! empty( $_REQUEST[ $action_key ] ) && is_string( $_REQUEST[ $action_key ] ) ) {
|
242 |
-
return strtolower( $_REQUEST[ $action_key ] );
|
243 |
-
}
|
244 |
-
}
|
245 |
-
|
246 |
-
return false;
|
247 |
-
}
|
248 |
-
}
|
249 |
-
|
250 |
-
if ( ! function_exists( 'fs_request_is_action' ) ) {
|
251 |
-
function fs_request_is_action( $action, $action_key = 'action' ) {
|
252 |
-
return ( strtolower( $action ) === fs_get_action( $action_key ) );
|
253 |
-
}
|
254 |
-
}
|
255 |
-
|
256 |
-
if ( ! function_exists( 'fs_request_is_action_secure' ) ) {
|
257 |
-
/**
|
258 |
-
* @author Vova Feldman (@svovaf)
|
259 |
-
* @since 1.0.0
|
260 |
-
*
|
261 |
-
* @since 1.2.1.5 Allow nonce verification.
|
262 |
-
*
|
263 |
-
* @param string $action
|
264 |
-
* @param string $action_key
|
265 |
-
* @param string $nonce_key
|
266 |
-
*
|
267 |
-
* @return bool
|
268 |
-
*/
|
269 |
-
function fs_request_is_action_secure(
|
270 |
-
$action,
|
271 |
-
$action_key = 'action',
|
272 |
-
$nonce_key = 'nonce'
|
273 |
-
) {
|
274 |
-
if ( strtolower( $action ) !== fs_get_action( $action_key ) ) {
|
275 |
-
return false;
|
276 |
-
}
|
277 |
-
|
278 |
-
$nonce = ! empty( $_REQUEST[ $nonce_key ] ) ?
|
279 |
-
$_REQUEST[ $nonce_key ] :
|
280 |
-
'';
|
281 |
-
|
282 |
-
if ( empty( $nonce ) ||
|
283 |
-
( false === wp_verify_nonce( $nonce, $action ) )
|
284 |
-
) {
|
285 |
-
return false;
|
286 |
-
}
|
287 |
-
|
288 |
-
return true;
|
289 |
-
}
|
290 |
-
}
|
291 |
-
|
292 |
-
#endregion
|
293 |
-
|
294 |
-
if ( ! function_exists( 'fs_is_plugin_page' ) ) {
|
295 |
-
function fs_is_plugin_page( $page_slug ) {
|
296 |
-
return ( is_admin() && $page_slug === fs_request_get( 'page' ) );
|
297 |
-
}
|
298 |
-
}
|
299 |
-
|
300 |
-
if ( ! function_exists( 'fs_get_raw_referer' ) ) {
|
301 |
-
/**
|
302 |
-
* Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
|
303 |
-
*
|
304 |
-
* Do not use for redirects, use {@see wp_get_referer()} instead.
|
305 |
-
*
|
306 |
-
* @since 1.2.3
|
307 |
-
*
|
308 |
-
* @return string|false Referer URL on success, false on failure.
|
309 |
-
*/
|
310 |
-
function fs_get_raw_referer() {
|
311 |
-
if ( function_exists( 'wp_get_raw_referer' ) ) {
|
312 |
-
return wp_get_raw_referer();
|
313 |
-
}
|
314 |
-
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
|
315 |
-
return wp_unslash( $_REQUEST['_wp_http_referer'] );
|
316 |
-
} else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
|
317 |
-
return wp_unslash( $_SERVER['HTTP_REFERER'] );
|
318 |
-
}
|
319 |
-
|
320 |
-
return false;
|
321 |
-
}
|
322 |
-
}
|
323 |
-
|
324 |
-
/* Core UI.
|
325 |
-
--------------------------------------------------------------------------------------------*/
|
326 |
-
if ( ! function_exists( 'fs_ui_action_button' ) ) {
|
327 |
-
/**
|
328 |
-
* @param number $module_id
|
329 |
-
* @param string $page
|
330 |
-
* @param string $action
|
331 |
-
* @param string $title
|
332 |
-
* @param string $button_class
|
333 |
-
* @param array $params
|
334 |
-
* @param bool $is_primary
|
335 |
-
* @param bool $is_small
|
336 |
-
* @param string|bool $icon_class Optional class for an icon (since 1.1.7).
|
337 |
-
* @param string|bool $confirmation Optional confirmation message before submit (since 1.1.7).
|
338 |
-
* @param string $method Since 1.1.7
|
339 |
-
*
|
340 |
-
* @uses fs_ui_get_action_button()
|
341 |
-
*/
|
342 |
-
function fs_ui_action_button(
|
343 |
-
$module_id,
|
344 |
-
$page,
|
345 |
-
$action,
|
346 |
-
$title,
|
347 |
-
$button_class = '',
|
348 |
-
$params = array(),
|
349 |
-
$is_primary = true,
|
350 |
-
$is_small = false,
|
351 |
-
$icon_class = false,
|
352 |
-
$confirmation = false,
|
353 |
-
$method = 'GET'
|
354 |
-
) {
|
355 |
-
echo fs_ui_get_action_button(
|
356 |
-
$module_id,
|
357 |
-
$page,
|
358 |
-
$action,
|
359 |
-
$title,
|
360 |
-
$button_class,
|
361 |
-
$params,
|
362 |
-
$is_primary,
|
363 |
-
$is_small,
|
364 |
-
$icon_class,
|
365 |
-
$confirmation,
|
366 |
-
$method
|
367 |
-
);
|
368 |
-
}
|
369 |
-
}
|
370 |
-
|
371 |
-
if ( ! function_exists( 'fs_ui_get_action_button' ) ) {
|
372 |
-
/**
|
373 |
-
* @author Vova Feldman (@svovaf)
|
374 |
-
* @since 1.1.7
|
375 |
-
*
|
376 |
-
* @param number $module_id
|
377 |
-
* @param string $page
|
378 |
-
* @param string $action
|
379 |
-
* @param string $title
|
380 |
-
* @param string $button_class
|
381 |
-
* @param array $params
|
382 |
-
* @param bool $is_primary
|
383 |
-
* @param bool $is_small
|
384 |
-
* @param string|bool $icon_class Optional class for an icon.
|
385 |
-
* @param string|bool $confirmation Optional confirmation message before submit.
|
386 |
-
* @param string $method
|
387 |
-
*
|
388 |
-
* @return string
|
389 |
-
*/
|
390 |
-
function fs_ui_get_action_button(
|
391 |
-
$module_id,
|
392 |
-
$page,
|
393 |
-
$action,
|
394 |
-
$title,
|
395 |
-
$button_class = '',
|
396 |
-
$params = array(),
|
397 |
-
$is_primary = true,
|
398 |
-
$is_small = false,
|
399 |
-
$icon_class = false,
|
400 |
-
$confirmation = false,
|
401 |
-
$method = 'GET'
|
402 |
-
) {
|
403 |
-
// Prepend icon (if set).
|
404 |
-
$title = ( is_string( $icon_class ) ? '<i class="' . $icon_class . '"></i> ' : '' ) . $title;
|
405 |
-
|
406 |
-
if ( is_string( $confirmation ) ) {
|
407 |
-
return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="if (confirm(\'%s\')) this.parentNode.submit(); return false;">%s</a></form>',
|
408 |
-
freemius( $module_id )->_get_admin_page_url( $page, $params ),
|
409 |
-
$method,
|
410 |
-
$action,
|
411 |
-
wp_nonce_field( $action, '_wpnonce', true, false ),
|
412 |
-
'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
|
413 |
-
$confirmation,
|
414 |
-
$title
|
415 |
-
);
|
416 |
-
} else if ( 'GET' !== strtoupper( $method ) ) {
|
417 |
-
return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="this.parentNode.submit(); return false;">%s</a></form>',
|
418 |
-
freemius( $module_id )->_get_admin_page_url( $page, $params ),
|
419 |
-
$method,
|
420 |
-
$action,
|
421 |
-
wp_nonce_field( $action, '_wpnonce', true, false ),
|
422 |
-
'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
|
423 |
-
$title
|
424 |
-
);
|
425 |
-
} else {
|
426 |
-
return sprintf( '<a href="%s" class="%s">%s</a></form>',
|
427 |
-
wp_nonce_url( freemius( $module_id )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ),
|
428 |
-
'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
|
429 |
-
$title
|
430 |
-
);
|
431 |
-
}
|
432 |
-
}
|
433 |
-
|
434 |
-
function fs_ui_action_link( $module_id, $page, $action, $title, $params = array() ) {
|
435 |
-
?><a class=""
|
436 |
-
href="<?php echo wp_nonce_url( freemius( $module_id )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ) ?>"><?php echo $title ?></a><?php
|
437 |
-
}
|
438 |
-
}
|
439 |
-
|
440 |
-
if ( ! function_exists( 'fs_get_entity' ) ) {
|
441 |
-
/**
|
442 |
-
* @author Leo Fajardo (@leorw)
|
443 |
-
* @since 2.3.1
|
444 |
-
*
|
445 |
-
* @param mixed $entity
|
446 |
-
* @param string $class
|
447 |
-
*
|
448 |
-
* @return FS_Plugin|FS_User|FS_Site|FS_Plugin_License|FS_Plugin_Plan|FS_Plugin_Tag|FS_Subscription
|
449 |
-
*/
|
450 |
-
function fs_get_entity( $entity, $class ) {
|
451 |
-
if ( ! is_object( $entity ) || $entity instanceof $class ) {
|
452 |
-
return $entity;
|
453 |
-
}
|
454 |
-
|
455 |
-
return new $class( $entity );
|
456 |
-
}
|
457 |
-
}
|
458 |
-
|
459 |
-
if ( ! function_exists( 'fs_get_entities' ) ) {
|
460 |
-
/**
|
461 |
-
* @author Leo Fajardo (@leorw)
|
462 |
-
* @since 2.3.1
|
463 |
-
*
|
464 |
-
* @param mixed $entities
|
465 |
-
* @param string $class_name
|
466 |
-
*
|
467 |
-
* @return FS_Plugin[]|FS_User[]|FS_Site[]|FS_Plugin_License[]|FS_Plugin_Plan[]|FS_Plugin_Tag[]|FS_Subscription[]
|
468 |
-
*/
|
469 |
-
function fs_get_entities( $entities, $class_name ) {
|
470 |
-
if ( ! is_array( $entities ) || empty( $entities ) ) {
|
471 |
-
return $entities;
|
472 |
-
}
|
473 |
-
|
474 |
-
// Get first element.
|
475 |
-
$first_array_element = reset( $entities );
|
476 |
-
|
477 |
-
if ( $first_array_element instanceof $class_name ) {
|
478 |
-
/**
|
479 |
-
* If the first element of the array is an instance of the context class, assume that all other
|
480 |
-
* elements are instances of the class.
|
481 |
-
*/
|
482 |
-
return $entities;
|
483 |
-
}
|
484 |
-
|
485 |
-
if (
|
486 |
-
is_array( $first_array_element ) &&
|
487 |
-
! empty( $first_array_element )
|
488 |
-
) {
|
489 |
-
$first_array_element = reset( $first_array_element );
|
490 |
-
|
491 |
-
if ( $first_array_element instanceof $class_name ) {
|
492 |
-
/**
|
493 |
-
* If the first element of the `$entities` array is an array whose first element is an instance of the
|
494 |
-
* context class, assume that all other objects are instances of the class.
|
495 |
-
*/
|
496 |
-
return $entities;
|
497 |
-
}
|
498 |
-
}
|
499 |
-
|
500 |
-
foreach ( $entities as $key => $entities_or_entity ) {
|
501 |
-
if ( is_array( $entities_or_entity ) ) {
|
502 |
-
$entities[ $key ] = fs_get_entities( $entities_or_entity, $class_name );
|
503 |
-
} else {
|
504 |
-
$entities[ $key ] = fs_get_entity( $entities_or_entity, $class_name );
|
505 |
-
}
|
506 |
-
}
|
507 |
-
|
508 |
-
return $entities;
|
509 |
-
}
|
510 |
-
}
|
511 |
-
|
512 |
-
if ( ! function_exists( 'fs_nonce_url' ) ) {
|
513 |
-
/**
|
514 |
-
* Retrieve URL with nonce added to URL query.
|
515 |
-
*
|
516 |
-
* Originally was using `wp_nonce_url()` but the new version
|
517 |
-
* changed the return value to escaped URL, that's not the expected
|
518 |
-
* behaviour.
|
519 |
-
*
|
520 |
-
* @author Vova Feldman (@svovaf)
|
521 |
-
* @since ~1.1.3
|
522 |
-
*
|
523 |
-
* @param string $actionurl URL to add nonce action.
|
524 |
-
* @param int|string $action Optional. Nonce action name. Default -1.
|
525 |
-
* @param string $name Optional. Nonce name. Default '_wpnonce'.
|
526 |
-
*
|
527 |
-
* @return string Escaped URL with nonce action added.
|
528 |
-
*/
|
529 |
-
function fs_nonce_url( $actionurl, $action = - 1, $name = '_wpnonce' ) {
|
530 |
-
return add_query_arg( $name, wp_create_nonce( $action ), $actionurl );
|
531 |
-
}
|
532 |
-
}
|
533 |
-
|
534 |
-
if ( ! function_exists( 'fs_starts_with' ) ) {
|
535 |
-
/**
|
536 |
-
* Check if string starts with.
|
537 |
-
*
|
538 |
-
* @author Vova Feldman (@svovaf)
|
539 |
-
* @since 1.1.3
|
540 |
-
*
|
541 |
-
* @param string $haystack
|
542 |
-
* @param string $needle
|
543 |
-
*
|
544 |
-
* @return bool
|
545 |
-
*/
|
546 |
-
function fs_starts_with( $haystack, $needle ) {
|
547 |
-
$length = strlen( $needle );
|
548 |
-
|
549 |
-
return ( substr( $haystack, 0, $length ) === $needle );
|
550 |
-
}
|
551 |
-
}
|
552 |
-
|
553 |
-
if ( ! function_exists( 'fs_ends_with' ) ) {
|
554 |
-
/**
|
555 |
-
* Check if string ends with.
|
556 |
-
*
|
557 |
-
* @author Vova Feldman (@svovaf)
|
558 |
-
* @since 2.0.0
|
559 |
-
*
|
560 |
-
* @param string $haystack
|
561 |
-
* @param string $needle
|
562 |
-
*
|
563 |
-
* @return bool
|
564 |
-
*/
|
565 |
-
function fs_ends_with( $haystack, $needle ) {
|
566 |
-
$length = strlen( $needle );
|
567 |
-
$start = $length * - 1; // negative
|
568 |
-
|
569 |
-
return ( substr( $haystack, $start ) === $needle );
|
570 |
-
}
|
571 |
-
}
|
572 |
-
|
573 |
-
if ( ! function_exists( 'fs_strip_url_protocol' ) ) {
|
574 |
-
function fs_strip_url_protocol( $url ) {
|
575 |
-
if ( ! fs_starts_with( $url, 'http' ) ) {
|
576 |
-
return $url;
|
577 |
-
}
|
578 |
-
|
579 |
-
$protocol_pos = strpos( $url, '://' );
|
580 |
-
|
581 |
-
if ( $protocol_pos > 5 ) {
|
582 |
-
return $url;
|
583 |
-
}
|
584 |
-
|
585 |
-
return substr( $url, $protocol_pos + 3 );
|
586 |
-
}
|
587 |
-
}
|
588 |
-
|
589 |
-
#region Url Canonization ------------------------------------------------------------------
|
590 |
-
|
591 |
-
if ( ! function_exists( 'fs_canonize_url' ) ) {
|
592 |
-
/**
|
593 |
-
* @author Vova Feldman (@svovaf)
|
594 |
-
* @since 1.1.3
|
595 |
-
*
|
596 |
-
* @param string $url
|
597 |
-
* @param bool $omit_host
|
598 |
-
* @param array $ignore_params
|
599 |
-
*
|
600 |
-
* @return string
|
601 |
-
*/
|
602 |
-
function fs_canonize_url( $url, $omit_host = false, $ignore_params = array() ) {
|
603 |
-
$parsed_url = parse_url( strtolower( $url ) );
|
604 |
-
|
605 |
-
// if ( ! isset( $parsed_url['host'] ) ) {
|
606 |
-
// return $url;
|
607 |
-
// }
|
608 |
-
|
609 |
-
$canonical = ( ( $omit_host || ! isset( $parsed_url['host'] ) ) ? '' : $parsed_url['host'] ) . $parsed_url['path'];
|
610 |
-
|
611 |
-
if ( isset( $parsed_url['query'] ) ) {
|
612 |
-
parse_str( $parsed_url['query'], $queryString );
|
613 |
-
$canonical .= '?' . fs_canonize_query_string( $queryString, $ignore_params );
|
614 |
-
}
|
615 |
-
|
616 |
-
return $canonical;
|
617 |
-
}
|
618 |
-
}
|
619 |
-
|
620 |
-
if ( ! function_exists( 'fs_canonize_query_string' ) ) {
|
621 |
-
/**
|
622 |
-
* @author Vova Feldman (@svovaf)
|
623 |
-
* @since 1.1.3
|
624 |
-
*
|
625 |
-
* @param array $params
|
626 |
-
* @param array $ignore_params
|
627 |
-
* @param bool $params_prefix
|
628 |
-
*
|
629 |
-
* @return string
|
630 |
-
*/
|
631 |
-
function fs_canonize_query_string( array $params, array &$ignore_params, $params_prefix = false ) {
|
632 |
-
if ( ! is_array( $params ) || 0 === count( $params ) ) {
|
633 |
-
return '';
|
634 |
-
}
|
635 |
-
|
636 |
-
// Url encode both keys and values
|
637 |
-
$keys = fs_urlencode_rfc3986( array_keys( $params ) );
|
638 |
-
$values = fs_urlencode_rfc3986( array_values( $params ) );
|
639 |
-
$params = array_combine( $keys, $values );
|
640 |
-
|
641 |
-
// Parameters are sorted by name, using lexicographical byte value ordering.
|
642 |
-
// Ref: Spec: 9.1.1 (1)
|
643 |
-
uksort( $params, 'strcmp' );
|
644 |
-
|
645 |
-
$pairs = array();
|
646 |
-
foreach ( $params as $parameter => $value ) {
|
647 |
-
$lower_param = strtolower( $parameter );
|
648 |
-
|
649 |
-
// Skip ignore params.
|
650 |
-
if ( in_array( $lower_param, $ignore_params ) ||
|
651 |
-
( false !== $params_prefix && fs_starts_with( $lower_param, $params_prefix ) )
|
652 |
-
) {
|
653 |
-
continue;
|
654 |
-
}
|
655 |
-
|
656 |
-
if ( is_array( $value ) ) {
|
657 |
-
// If two or more parameters share the same name, they are sorted by their value
|
658 |
-
// Ref: Spec: 9.1.1 (1)
|
659 |
-
natsort( $value );
|
660 |
-
foreach ( $value as $duplicate_value ) {
|
661 |
-
$pairs[] = $lower_param . '=' . $duplicate_value;
|
662 |
-
}
|
663 |
-
} else {
|
664 |
-
$pairs[] = $lower_param . '=' . $value;
|
665 |
-
}
|
666 |
-
}
|
667 |
-
|
668 |
-
if ( 0 === count( $pairs ) ) {
|
669 |
-
return '';
|
670 |
-
}
|
671 |
-
|
672 |
-
return implode( "&", $pairs );
|
673 |
-
}
|
674 |
-
}
|
675 |
-
|
676 |
-
if ( ! function_exists( 'fs_urlencode_rfc3986' ) ) {
|
677 |
-
/**
|
678 |
-
* @author Vova Feldman (@svovaf)
|
679 |
-
* @since 1.1.3
|
680 |
-
*
|
681 |
-
* @param string|string[] $input
|
682 |
-
*
|
683 |
-
* @return array|mixed|string
|
684 |
-
*/
|
685 |
-
function fs_urlencode_rfc3986( $input ) {
|
686 |
-
if ( is_array( $input ) ) {
|
687 |
-
return array_map( 'fs_urlencode_rfc3986', $input );
|
688 |
-
} else if ( is_scalar( $input ) ) {
|
689 |
-
return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
|
690 |
-
}
|
691 |
-
|
692 |
-
return '';
|
693 |
-
}
|
694 |
-
}
|
695 |
-
|
696 |
-
#endregion Url Canonization ------------------------------------------------------------------
|
697 |
-
|
698 |
-
if ( ! function_exists( 'fs_download_image' ) ) {
|
699 |
-
/**
|
700 |
-
* @author Vova Feldman (@svovaf)
|
701 |
-
*
|
702 |
-
* @since 1.2.2 Changed to usage of WP_Filesystem_Direct.
|
703 |
-
*
|
704 |
-
* @param string $from URL
|
705 |
-
* @param string $to File path.
|
706 |
-
*
|
707 |
-
* @return bool Is successfully downloaded.
|
708 |
-
*/
|
709 |
-
function fs_download_image( $from, $to ) {
|
710 |
-
$dir = dirname( $to );
|
711 |
-
|
712 |
-
if ( 'direct' !== get_filesystem_method( array(), $dir ) ) {
|
713 |
-
return false;
|
714 |
-
}
|
715 |
-
|
716 |
-
if ( ! class_exists( 'WP_Filesystem_Direct' ) ) {
|
717 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
|
718 |
-
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
|
719 |
-
}
|
720 |
-
|
721 |
-
$fs = new WP_Filesystem_Direct( '' );
|
722 |
-
$tmpfile = download_url( $from );
|
723 |
-
|
724 |
-
if ( $tmpfile instanceof WP_Error ) {
|
725 |
-
// Issue downloading the file.
|
726 |
-
return false;
|
727 |
-
}
|
728 |
-
|
729 |
-
$fs->copy( $tmpfile, $to );
|
730 |
-
$fs->delete( $tmpfile );
|
731 |
-
|
732 |
-
return true;
|
733 |
-
}
|
734 |
-
}
|
735 |
-
|
736 |
-
/* General Utilities
|
737 |
-
--------------------------------------------------------------------------------------------*/
|
738 |
-
|
739 |
-
if ( ! function_exists( 'fs_sort_by_priority' ) ) {
|
740 |
-
/**
|
741 |
-
* Sorts an array by the value of the priority key.
|
742 |
-
*
|
743 |
-
* @author Daniel Iser (@danieliser)
|
744 |
-
* @since 1.1.7
|
745 |
-
*
|
746 |
-
* @param $a
|
747 |
-
* @param $b
|
748 |
-
*
|
749 |
-
* @return int
|
750 |
-
*/
|
751 |
-
function fs_sort_by_priority( $a, $b ) {
|
752 |
-
|
753 |
-
// If b has a priority and a does not, b wins.
|
754 |
-
if ( ! isset( $a['priority'] ) && isset( $b['priority'] ) ) {
|
755 |
-
return 1;
|
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 |
-
}
|
763 |
-
|
764 |
-
// If both have priority return the winner.
|
765 |
-
return ( $a['priority'] < $b['priority'] ) ? - 1 : 1;
|
766 |
-
}
|
767 |
-
}
|
768 |
-
|
769 |
-
#--------------------------------------------------------------------------------
|
770 |
-
#region Localization
|
771 |
-
#--------------------------------------------------------------------------------
|
772 |
-
|
773 |
-
if ( ! function_exists( 'fs_text' ) ) {
|
774 |
-
/**
|
775 |
-
* Retrieve a translated text by key.
|
776 |
-
*
|
777 |
-
* @author Vova Feldman (@svovaf)
|
778 |
-
* @since 1.2.1.7
|
779 |
-
*
|
780 |
-
* @param string $key
|
781 |
-
* @param string $slug
|
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 ] ) ) {
|
794 |
-
return $fs_text_overrides[ $slug ][ $key ];
|
795 |
-
}
|
796 |
-
|
797 |
-
$lower_key = strtolower( $key );
|
798 |
-
if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
|
799 |
-
return $fs_text_overrides[ $slug ][ $lower_key ];
|
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 |
-
|
822 |
-
#region Private
|
823 |
-
|
824 |
-
/**
|
825 |
-
* Retrieve an inline translated text by key with a context.
|
826 |
-
*
|
827 |
-
* @author Vova Feldman (@svovaf)
|
828 |
-
* @since 1.2.3
|
829 |
-
*
|
830 |
-
* @param string $text Translatable string.
|
831 |
-
* @param string $context Context information for the translators.
|
832 |
-
* @param string $key String key for overrides.
|
833 |
-
* @param string $slug Module slug for overrides.
|
834 |
-
*
|
835 |
-
* @return string
|
836 |
-
*
|
837 |
-
* @global $fs_text_overrides
|
838 |
-
*/
|
839 |
-
function _fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
840 |
-
list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
|
841 |
-
|
842 |
-
// Avoid misleading Theme Check warning.
|
843 |
-
$fn = 'translate_with_gettext_context';
|
844 |
-
|
845 |
-
return $fn( $text, $context, $text_domain );
|
846 |
-
}
|
847 |
-
|
848 |
-
#endregion
|
849 |
-
|
850 |
-
/**
|
851 |
-
* Retrieve an inline translated text by key with a context.
|
852 |
-
*
|
853 |
-
* @author Vova Feldman (@svovaf)
|
854 |
-
* @since 1.2.3
|
855 |
-
*
|
856 |
-
* @param string $text Translatable string.
|
857 |
-
* @param string $context Context information for the translators.
|
858 |
-
* @param string $key String key for overrides.
|
859 |
-
* @param string $slug Module slug for overrides.
|
860 |
-
*
|
861 |
-
* @return string
|
862 |
-
*
|
863 |
-
* @global $fs_text_overrides
|
864 |
-
*/
|
865 |
-
function fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
866 |
-
return _fs_text_x_inline( $text, $context, $key, $slug );
|
867 |
-
}
|
868 |
-
|
869 |
-
/**
|
870 |
-
* Output a translated text by key.
|
871 |
-
*
|
872 |
-
* @author Vova Feldman (@svovaf)
|
873 |
-
* @since 1.2.1.7
|
874 |
-
*
|
875 |
-
* @param string $key
|
876 |
-
* @param string $slug
|
877 |
-
*/
|
878 |
-
function fs_echo( $key, $slug = 'freemius' ) {
|
879 |
-
echo fs_text( $key, $slug );
|
880 |
-
}
|
881 |
-
|
882 |
-
/**
|
883 |
-
* Output an inline translated text.
|
884 |
-
*
|
885 |
-
* @author Vova Feldman (@svovaf)
|
886 |
-
* @since 1.2.3
|
887 |
-
*
|
888 |
-
* @param string $text Translatable string.
|
889 |
-
* @param string $key String key for overrides.
|
890 |
-
* @param string $slug Module slug for overrides.
|
891 |
-
*/
|
892 |
-
function fs_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
893 |
-
echo _fs_text_inline( $text, $key, $slug );
|
894 |
-
}
|
895 |
-
|
896 |
-
/**
|
897 |
-
* Output an inline translated text with a context.
|
898 |
-
*
|
899 |
-
* @author Vova Feldman (@svovaf)
|
900 |
-
* @since 1.2.3
|
901 |
-
*
|
902 |
-
* @param string $text Translatable string.
|
903 |
-
* @param string $context Context information for the translators.
|
904 |
-
* @param string $key String key for overrides.
|
905 |
-
* @param string $slug Module slug for overrides.
|
906 |
-
*/
|
907 |
-
function fs_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
908 |
-
echo _fs_text_x_inline( $text, $context, $key, $slug );
|
909 |
-
}
|
910 |
-
}
|
911 |
-
|
912 |
-
if ( ! function_exists( 'fs_text_override' ) ) {
|
913 |
-
/**
|
914 |
-
* Get a translatable text override if exists, or `false`.
|
915 |
-
*
|
916 |
-
* @author Vova Feldman (@svovaf)
|
917 |
-
* @since 1.2.1.7
|
918 |
-
*
|
919 |
-
* @param string $text Translatable string.
|
920 |
-
* @param string $key String key for overrides.
|
921 |
-
* @param string $slug Module slug for overrides.
|
922 |
-
*
|
923 |
-
* @return string|false
|
924 |
-
*/
|
925 |
-
function fs_text_override( $text, $key, $slug ) {
|
926 |
-
global $fs_text_overrides;
|
927 |
-
|
928 |
-
/**
|
929 |
-
* Check if string is overridden.
|
930 |
-
*/
|
931 |
-
if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
|
932 |
-
return false;
|
933 |
-
}
|
934 |
-
|
935 |
-
if ( empty( $key ) ) {
|
936 |
-
$key = strtolower( str_replace( ' ', '-', $text ) );
|
937 |
-
}
|
938 |
-
|
939 |
-
if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
|
940 |
-
return $fs_text_overrides[ $slug ][ $key ];
|
941 |
-
}
|
942 |
-
|
943 |
-
$lower_key = strtolower( $key );
|
944 |
-
if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
|
945 |
-
return $fs_text_overrides[ $slug ][ $lower_key ];
|
946 |
-
}
|
947 |
-
|
948 |
-
return false;
|
949 |
-
}
|
950 |
-
}
|
951 |
-
|
952 |
-
if ( ! function_exists( 'fs_text_and_domain' ) ) {
|
953 |
-
/**
|
954 |
-
* Get a translatable text and its text domain.
|
955 |
-
*
|
956 |
-
* When the text is overridden by the module, returns the overridden text and the text domain of the module. Otherwise, returns the original text and 'freemius' as the text domain.
|
957 |
-
*
|
958 |
-
* @author Vova Feldman (@svovaf)
|
959 |
-
* @since 1.2.1.7
|
960 |
-
*
|
961 |
-
* @param string $text Translatable string.
|
962 |
-
* @param string $key String key for overrides.
|
963 |
-
* @param string $slug Module slug for overrides.
|
964 |
-
*
|
965 |
-
* @return string[]
|
966 |
-
*/
|
967 |
-
function fs_text_and_domain( $text, $key, $slug ) {
|
968 |
-
$override = fs_text_override( $text, $key, $slug );
|
969 |
-
|
970 |
-
if ( false === $override ) {
|
971 |
-
// No override, use FS text domain.
|
972 |
-
$text_domain = 'freemius';
|
973 |
-
} else {
|
974 |
-
// Found an override.
|
975 |
-
$text = $override;
|
976 |
-
// Use the module's text domain.
|
977 |
-
$text_domain = $slug;
|
978 |
-
}
|
979 |
-
|
980 |
-
return array( $text, $text_domain );
|
981 |
-
}
|
982 |
-
}
|
983 |
-
|
984 |
-
if ( ! function_exists( '_fs_text_inline' ) ) {
|
985 |
-
/**
|
986 |
-
* Retrieve an inline translated text by key.
|
987 |
-
*
|
988 |
-
* @author Vova Feldman (@svovaf)
|
989 |
-
* @since 1.2.3
|
990 |
-
*
|
991 |
-
* @param string $text Translatable string.
|
992 |
-
* @param string $key String key for overrides.
|
993 |
-
* @param string $slug Module slug for overrides.
|
994 |
-
*
|
995 |
-
* @return string
|
996 |
-
*
|
997 |
-
* @global $fs_text_overrides
|
998 |
-
*/
|
999 |
-
function _fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
|
1000 |
-
list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
|
1001 |
-
|
1002 |
-
// Avoid misleading Theme Check warning.
|
1003 |
-
$fn = 'translate';
|
1004 |
-
|
1005 |
-
return $fn( $text, $text_domain );
|
1006 |
-
}
|
1007 |
-
}
|
1008 |
-
|
1009 |
-
if ( ! function_exists( 'fs_text_inline' ) ) {
|
1010 |
-
/**
|
1011 |
-
* Retrieve an inline translated text by key.
|
1012 |
-
*
|
1013 |
-
* @author Vova Feldman (@svovaf)
|
1014 |
-
* @since 1.2.3
|
1015 |
-
*
|
1016 |
-
* @param string $text Translatable string.
|
1017 |
-
* @param string $key String key for overrides.
|
1018 |
-
* @param string $slug Module slug for overrides.
|
1019 |
-
*
|
1020 |
-
* @return string
|
1021 |
-
*
|
1022 |
-
* @global $fs_text_overrides
|
1023 |
-
*/
|
1024 |
-
function fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
|
1025 |
-
return _fs_text_inline( $text, $key, $slug );
|
1026 |
-
}
|
1027 |
-
}
|
1028 |
-
|
1029 |
-
if ( ! function_exists( 'fs_esc_attr' ) ) {
|
1030 |
-
/**
|
1031 |
-
* @author Vova Feldman
|
1032 |
-
* @since 1.2.1.6
|
1033 |
-
*
|
1034 |
-
* @param string $key
|
1035 |
-
* @param string $slug
|
1036 |
-
*
|
1037 |
-
* @return string
|
1038 |
-
*/
|
1039 |
-
function fs_esc_attr( $key, $slug ) {
|
1040 |
-
return esc_attr( fs_text( $key, $slug ) );
|
1041 |
-
}
|
1042 |
-
}
|
1043 |
-
|
1044 |
-
if ( ! function_exists( 'fs_esc_attr_inline' ) ) {
|
1045 |
-
/**
|
1046 |
-
* @author Vova Feldman (@svovaf)
|
1047 |
-
* @since 1.2.3
|
1048 |
-
*
|
1049 |
-
* @param string $text Translatable string.
|
1050 |
-
* @param string $key String key for overrides.
|
1051 |
-
* @param string $slug Module slug for overrides.
|
1052 |
-
*
|
1053 |
-
* @return string
|
1054 |
-
*/
|
1055 |
-
function fs_esc_attr_inline( $text, $key = '', $slug = 'freemius' ) {
|
1056 |
-
return esc_attr( _fs_text_inline( $text, $key, $slug ) );
|
1057 |
-
}
|
1058 |
-
}
|
1059 |
-
|
1060 |
-
if ( ! function_exists( 'fs_esc_attr_x_inline' ) ) {
|
1061 |
-
/**
|
1062 |
-
* @author Vova Feldman (@svovaf)
|
1063 |
-
* @since 1.2.3
|
1064 |
-
*
|
1065 |
-
* @param string $text Translatable string.
|
1066 |
-
* @param string $context Context information for the translators.
|
1067 |
-
* @param string $key String key for overrides.
|
1068 |
-
* @param string $slug Module slug for overrides.
|
1069 |
-
*
|
1070 |
-
* @return string
|
1071 |
-
*/
|
1072 |
-
function fs_esc_attr_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1073 |
-
return esc_attr( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1074 |
-
}
|
1075 |
-
}
|
1076 |
-
|
1077 |
-
if ( ! function_exists( 'fs_esc_attr_echo' ) ) {
|
1078 |
-
/**
|
1079 |
-
* @author Vova Feldman
|
1080 |
-
* @since 1.2.1.6
|
1081 |
-
*
|
1082 |
-
* @param string $key
|
1083 |
-
* @param string $slug
|
1084 |
-
*/
|
1085 |
-
function fs_esc_attr_echo( $key, $slug ) {
|
1086 |
-
echo esc_attr( fs_text( $key, $slug ) );
|
1087 |
-
}
|
1088 |
-
}
|
1089 |
-
|
1090 |
-
if ( ! function_exists( 'fs_esc_attr_echo_inline' ) ) {
|
1091 |
-
/**
|
1092 |
-
* @author Vova Feldman (@svovaf)
|
1093 |
-
* @since 1.2.3
|
1094 |
-
*
|
1095 |
-
* @param string $text Translatable string.
|
1096 |
-
* @param string $key String key for overrides.
|
1097 |
-
* @param string $slug Module slug for overrides.
|
1098 |
-
*/
|
1099 |
-
function fs_esc_attr_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1100 |
-
echo esc_attr( _fs_text_inline( $text, $key, $slug ) );
|
1101 |
-
}
|
1102 |
-
}
|
1103 |
-
|
1104 |
-
if ( ! function_exists( 'fs_esc_js' ) ) {
|
1105 |
-
/**
|
1106 |
-
* @author Vova Feldman
|
1107 |
-
* @since 1.2.1.6
|
1108 |
-
*
|
1109 |
-
* @param string $key
|
1110 |
-
* @param string $slug
|
1111 |
-
*
|
1112 |
-
* @return string
|
1113 |
-
*/
|
1114 |
-
function fs_esc_js( $key, $slug ) {
|
1115 |
-
return esc_js( fs_text( $key, $slug ) );
|
1116 |
-
}
|
1117 |
-
}
|
1118 |
-
|
1119 |
-
if ( ! function_exists( 'fs_esc_js_inline' ) ) {
|
1120 |
-
/**
|
1121 |
-
* @author Vova Feldman (@svovaf)
|
1122 |
-
* @since 1.2.3
|
1123 |
-
*
|
1124 |
-
* @param string $text Translatable string.
|
1125 |
-
* @param string $key String key for overrides.
|
1126 |
-
* @param string $slug Module slug for overrides.
|
1127 |
-
*
|
1128 |
-
* @return string
|
1129 |
-
*/
|
1130 |
-
function fs_esc_js_inline( $text, $key = '', $slug = 'freemius' ) {
|
1131 |
-
return esc_js( _fs_text_inline( $text, $key, $slug ) );
|
1132 |
-
}
|
1133 |
-
}
|
1134 |
-
|
1135 |
-
if ( ! function_exists( 'fs_esc_js_x_inline' ) ) {
|
1136 |
-
/**
|
1137 |
-
* @author Vova Feldman (@svovaf)
|
1138 |
-
* @since 1.2.3
|
1139 |
-
*
|
1140 |
-
* @param string $text Translatable string.
|
1141 |
-
* @param string $context Context information for the translators.
|
1142 |
-
* @param string $key String key for overrides.
|
1143 |
-
* @param string $slug Module slug for overrides.
|
1144 |
-
*
|
1145 |
-
* @return string
|
1146 |
-
*/
|
1147 |
-
function fs_esc_js_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1148 |
-
return esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1149 |
-
}
|
1150 |
-
}
|
1151 |
-
|
1152 |
-
if ( ! function_exists( 'fs_esc_js_echo_x_inline' ) ) {
|
1153 |
-
/**
|
1154 |
-
* @author Vova Feldman (@svovaf)
|
1155 |
-
* @since 1.2.3
|
1156 |
-
*
|
1157 |
-
* @param string $text Translatable string.
|
1158 |
-
* @param string $context Context information for the translators.
|
1159 |
-
* @param string $key String key for overrides.
|
1160 |
-
* @param string $slug Module slug for overrides.
|
1161 |
-
*
|
1162 |
-
* @return string
|
1163 |
-
*/
|
1164 |
-
function fs_esc_js_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1165 |
-
echo esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1166 |
-
}
|
1167 |
-
}
|
1168 |
-
|
1169 |
-
if ( ! function_exists( 'fs_esc_js_echo' ) ) {
|
1170 |
-
/**
|
1171 |
-
* @author Vova Feldman
|
1172 |
-
* @since 1.2.1.6
|
1173 |
-
*
|
1174 |
-
* @param string $key
|
1175 |
-
* @param string $slug
|
1176 |
-
*/
|
1177 |
-
function fs_esc_js_echo( $key, $slug ) {
|
1178 |
-
echo esc_js( fs_text( $key, $slug ) );
|
1179 |
-
}
|
1180 |
-
}
|
1181 |
-
|
1182 |
-
if ( ! function_exists( 'fs_esc_js_echo_inline' ) ) {
|
1183 |
-
/**
|
1184 |
-
* @author Vova Feldman (@svovaf)
|
1185 |
-
* @since 1.2.3
|
1186 |
-
*
|
1187 |
-
* @param string $text Translatable string.
|
1188 |
-
* @param string $key String key for overrides.
|
1189 |
-
* @param string $slug Module slug for overrides.
|
1190 |
-
*/
|
1191 |
-
function fs_esc_js_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1192 |
-
echo esc_js( _fs_text_inline( $text, $key, $slug ) );
|
1193 |
-
}
|
1194 |
-
}
|
1195 |
-
|
1196 |
-
if ( ! function_exists( 'fs_json_encode_echo' ) ) {
|
1197 |
-
/**
|
1198 |
-
* @author Vova Feldman
|
1199 |
-
* @since 1.2.1.6
|
1200 |
-
*
|
1201 |
-
* @param string $key
|
1202 |
-
* @param string $slug
|
1203 |
-
*/
|
1204 |
-
function fs_json_encode_echo( $key, $slug ) {
|
1205 |
-
echo json_encode( fs_text( $key, $slug ) );
|
1206 |
-
}
|
1207 |
-
}
|
1208 |
-
|
1209 |
-
if ( ! function_exists( 'fs_json_encode_echo_inline' ) ) {
|
1210 |
-
/**
|
1211 |
-
* @author Vova Feldman (@svovaf)
|
1212 |
-
* @since 1.2.3
|
1213 |
-
*
|
1214 |
-
* @param string $text Translatable string.
|
1215 |
-
* @param string $key String key for overrides.
|
1216 |
-
* @param string $slug Module slug for overrides.
|
1217 |
-
*/
|
1218 |
-
function fs_json_encode_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1219 |
-
echo json_encode( _fs_text_inline( $text, $key, $slug ) );
|
1220 |
-
}
|
1221 |
-
}
|
1222 |
-
|
1223 |
-
if ( ! function_exists( 'fs_esc_html' ) ) {
|
1224 |
-
/**
|
1225 |
-
* @author Vova Feldman
|
1226 |
-
* @since 1.2.1.6
|
1227 |
-
*
|
1228 |
-
* @param string $key
|
1229 |
-
* @param string $slug
|
1230 |
-
*
|
1231 |
-
* @return string
|
1232 |
-
*/
|
1233 |
-
function fs_esc_html( $key, $slug ) {
|
1234 |
-
return esc_html( fs_text( $key, $slug ) );
|
1235 |
-
}
|
1236 |
-
}
|
1237 |
-
|
1238 |
-
if ( ! function_exists( 'fs_esc_html_inline' ) ) {
|
1239 |
-
/**
|
1240 |
-
* @author Vova Feldman (@svovaf)
|
1241 |
-
* @since 1.2.3
|
1242 |
-
*
|
1243 |
-
* @param string $text Translatable string.
|
1244 |
-
* @param string $key String key for overrides.
|
1245 |
-
* @param string $slug Module slug for overrides.
|
1246 |
-
*
|
1247 |
-
* @return string
|
1248 |
-
*/
|
1249 |
-
function fs_esc_html_inline( $text, $key = '', $slug = 'freemius' ) {
|
1250 |
-
return esc_html( _fs_text_inline( $text, $key, $slug ) );
|
1251 |
-
}
|
1252 |
-
}
|
1253 |
-
|
1254 |
-
if ( ! function_exists( 'fs_esc_html_x_inline' ) ) {
|
1255 |
-
/**
|
1256 |
-
* @author Vova Feldman (@svovaf)
|
1257 |
-
* @since 1.2.3
|
1258 |
-
*
|
1259 |
-
* @param string $text Translatable string.
|
1260 |
-
* @param string $context Context information for the translators.
|
1261 |
-
* @param string $key String key for overrides.
|
1262 |
-
* @param string $slug Module slug for overrides.
|
1263 |
-
*
|
1264 |
-
* @return string
|
1265 |
-
*/
|
1266 |
-
function fs_esc_html_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1267 |
-
return esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1268 |
-
}
|
1269 |
-
}
|
1270 |
-
|
1271 |
-
if ( ! function_exists( 'fs_esc_html_echo_x_inline' ) ) {
|
1272 |
-
/**
|
1273 |
-
* @author Vova Feldman (@svovaf)
|
1274 |
-
* @since 1.2.3
|
1275 |
-
*
|
1276 |
-
* @param string $text Translatable string.
|
1277 |
-
* @param string $context Context information for the translators.
|
1278 |
-
* @param string $key String key for overrides.
|
1279 |
-
* @param string $slug Module slug for overrides.
|
1280 |
-
*/
|
1281 |
-
function fs_esc_html_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1282 |
-
echo esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1283 |
-
}
|
1284 |
-
}
|
1285 |
-
|
1286 |
-
if ( ! function_exists( 'fs_esc_html_echo' ) ) {
|
1287 |
-
/**
|
1288 |
-
* @author Vova Feldman
|
1289 |
-
* @since 1.2.1.6
|
1290 |
-
*
|
1291 |
-
* @param string $key
|
1292 |
-
* @param string $slug
|
1293 |
-
*/
|
1294 |
-
function fs_esc_html_echo( $key, $slug ) {
|
1295 |
-
echo esc_html( fs_text( $key, $slug ) );
|
1296 |
-
}
|
1297 |
-
}
|
1298 |
-
|
1299 |
-
if ( ! function_exists( 'fs_esc_html_echo_inline' ) ) {
|
1300 |
-
/**
|
1301 |
-
* @author Vova Feldman (@svovaf)
|
1302 |
-
* @since 1.2.3
|
1303 |
-
*
|
1304 |
-
* @param string $text Translatable string.
|
1305 |
-
* @param string $key String key for overrides.
|
1306 |
-
* @param string $slug Module slug for overrides.
|
1307 |
-
*/
|
1308 |
-
function fs_esc_html_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1309 |
-
echo esc_html( _fs_text_inline( $text, $key, $slug ) );
|
1310 |
-
}
|
1311 |
-
}
|
1312 |
-
|
1313 |
-
if ( ! function_exists( 'fs_override_i18n' ) ) {
|
1314 |
-
/**
|
1315 |
-
* Override default i18n text phrases.
|
1316 |
-
*
|
1317 |
-
* @author Vova Feldman (@svovaf)
|
1318 |
-
* @since 1.1.6
|
1319 |
-
*
|
1320 |
-
* @param array[string]string $key_value
|
1321 |
-
* @param string $slug
|
1322 |
-
*
|
1323 |
-
* @global $fs_text_overrides
|
1324 |
-
*/
|
1325 |
-
function fs_override_i18n( array $key_value, $slug = 'freemius' ) {
|
1326 |
-
global $fs_text_overrides;
|
1327 |
-
|
1328 |
-
if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
|
1329 |
-
$fs_text_overrides[ $slug ] = array();
|
1330 |
-
}
|
1331 |
-
|
1332 |
-
foreach ( $key_value as $key => $value ) {
|
1333 |
-
$fs_text_overrides[ $slug ][ $key ] = $value;
|
1334 |
-
}
|
1335 |
-
}
|
1336 |
-
}
|
1337 |
-
|
1338 |
-
#endregion
|
1339 |
-
|
1340 |
-
#--------------------------------------------------------------------------------
|
1341 |
-
#region Multisite Network
|
1342 |
-
#--------------------------------------------------------------------------------
|
1343 |
-
|
1344 |
-
if ( ! function_exists( 'fs_is_plugin_uninstall' ) ) {
|
1345 |
-
/**
|
1346 |
-
* @author Vova Feldman (@svovaf)
|
1347 |
-
* @since 2.0.0
|
1348 |
-
*/
|
1349 |
-
function fs_is_plugin_uninstall() {
|
1350 |
-
return (
|
1351 |
-
defined( 'WP_UNINSTALL_PLUGIN' ) ||
|
1352 |
-
( 0 < did_action( 'update_option_uninstall_plugins' ) )
|
1353 |
-
);
|
1354 |
-
}
|
1355 |
-
}
|
1356 |
-
|
1357 |
-
if ( ! function_exists( 'fs_is_network_admin' ) ) {
|
1358 |
-
/**
|
1359 |
-
* Unlike is_network_admin(), this one will also work properly when
|
1360 |
-
* the context execution is WP AJAX handler, and during plugin
|
1361 |
-
* uninstall.
|
1362 |
-
*
|
1363 |
-
* @author Vova Feldman (@svovaf)
|
1364 |
-
* @since 2.0.0
|
1365 |
-
*/
|
1366 |
-
function fs_is_network_admin() {
|
1367 |
-
return (
|
1368 |
-
WP_FS__IS_NETWORK_ADMIN ||
|
1369 |
-
( is_multisite() && fs_is_plugin_uninstall() )
|
1370 |
-
);
|
1371 |
-
}
|
1372 |
-
}
|
1373 |
-
|
1374 |
-
if ( ! function_exists( 'fs_is_blog_admin' ) ) {
|
1375 |
-
/**
|
1376 |
-
* Unlike is_blog_admin(), this one will also work properly when
|
1377 |
-
* the context execution is WP AJAX handler, and during plugin
|
1378 |
-
* uninstall.
|
1379 |
-
*
|
1380 |
-
* @author Vova Feldman (@svovaf)
|
1381 |
-
* @since 2.0.0
|
1382 |
-
*/
|
1383 |
-
function fs_is_blog_admin() {
|
1384 |
-
return (
|
1385 |
-
WP_FS__IS_BLOG_ADMIN ||
|
1386 |
-
( ! is_multisite() && fs_is_plugin_uninstall() )
|
1387 |
-
);
|
1388 |
-
}
|
1389 |
-
}
|
1390 |
-
|
1391 |
-
#endregion
|
1392 |
-
|
1393 |
-
if ( ! function_exists( 'fs_apply_filter' ) ) {
|
1394 |
-
/**
|
1395 |
-
* Apply filter for specific plugin.
|
1396 |
-
*
|
1397 |
-
* @author Vova Feldman (@svovaf)
|
1398 |
-
* @since 1.0.9
|
1399 |
-
*
|
1400 |
-
* @param string $module_unique_affix Module's unique affix.
|
1401 |
-
* @param string $tag The name of the filter hook.
|
1402 |
-
* @param mixed $value The value on which the filters hooked to `$tag` are applied on.
|
1403 |
-
*
|
1404 |
-
* @return mixed The filtered value after all hooked functions are applied to it.
|
1405 |
-
*
|
1406 |
-
* @uses apply_filters()
|
1407 |
-
*/
|
1408 |
-
function fs_apply_filter( $module_unique_affix, $tag, $value ) {
|
1409 |
-
$args = func_get_args();
|
1410 |
-
|
1411 |
-
return call_user_func_array( 'apply_filters', array_merge(
|
1412 |
-
array( "fs_{$tag}_{$module_unique_affix}" ),
|
1413 |
-
array_slice( $args, 2 ) )
|
1414 |
-
);
|
1415 |
-
}
|
1416 |
}
|
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 1.0.3
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
if ( ! function_exists( 'fs_dummy' ) ) {
|
14 |
+
function fs_dummy() {
|
15 |
+
}
|
16 |
+
}
|
17 |
+
|
18 |
+
/* Url.
|
19 |
+
--------------------------------------------------------------------------------------------*/
|
20 |
+
if ( ! function_exists( 'fs_get_url_daily_cache_killer' ) ) {
|
21 |
+
function fs_get_url_daily_cache_killer() {
|
22 |
+
return date( '\YY\Mm\Dd' );
|
23 |
+
}
|
24 |
+
}
|
25 |
+
|
26 |
+
/* Templates / Views.
|
27 |
+
--------------------------------------------------------------------------------------------*/
|
28 |
+
if ( ! function_exists( 'fs_get_template_path' ) ) {
|
29 |
+
function fs_get_template_path( $path ) {
|
30 |
+
return WP_FS__DIR_TEMPLATES . '/' . trim( $path, '/' );
|
31 |
+
}
|
32 |
+
|
33 |
+
function fs_include_template( $path, &$params = null ) {
|
34 |
+
$VARS = &$params;
|
35 |
+
include fs_get_template_path( $path );
|
36 |
+
}
|
37 |
+
|
38 |
+
function fs_include_once_template( $path, &$params = null ) {
|
39 |
+
$VARS = &$params;
|
40 |
+
include_once fs_get_template_path( $path );
|
41 |
+
}
|
42 |
+
|
43 |
+
function fs_require_template( $path, &$params = null ) {
|
44 |
+
$VARS = &$params;
|
45 |
+
require fs_get_template_path( $path );
|
46 |
+
}
|
47 |
+
|
48 |
+
function fs_require_once_template( $path, &$params = null ) {
|
49 |
+
$VARS = &$params;
|
50 |
+
require_once fs_get_template_path( $path );
|
51 |
+
}
|
52 |
+
|
53 |
+
function fs_get_template( $path, &$params = null ) {
|
54 |
+
ob_start();
|
55 |
+
|
56 |
+
$VARS = &$params;
|
57 |
+
require fs_get_template_path( $path );
|
58 |
+
|
59 |
+
return ob_get_clean();
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
/* Scripts and styles including.
|
64 |
+
--------------------------------------------------------------------------------------------*/
|
65 |
+
|
66 |
+
if ( ! function_exists( 'fs_asset_url' ) ) {
|
67 |
+
/**
|
68 |
+
* Generates an absolute URL to the given path. This function ensures that the URL will be correct whether the asset
|
69 |
+
* is inside a plugin's folder or a theme's folder.
|
70 |
+
*
|
71 |
+
* Examples:
|
72 |
+
* 1. "themes" folder
|
73 |
+
* Path: C:/xampp/htdocs/fswp/wp-content/themes/twentytwelve/freemius/assets/css/admin/common.css
|
74 |
+
* URL: http://fswp:8080/wp-content/themes/twentytwelve/freemius/assets/css/admin/common.css
|
75 |
+
*
|
76 |
+
* 2. "plugins" folder
|
77 |
+
* Path: C:/xampp/htdocs/fswp/wp-content/plugins/rating-widget-premium/freemius/assets/css/admin/common.css
|
78 |
+
* URL: http://fswp:8080/wp-content/plugins/rating-widget-premium/freemius/assets/css/admin/common.css
|
79 |
+
*
|
80 |
+
* @author Leo Fajardo (@leorw)
|
81 |
+
* @since 1.2.2
|
82 |
+
*
|
83 |
+
* @param string $asset_abs_path Asset's absolute path.
|
84 |
+
*
|
85 |
+
* @return string Asset's URL.
|
86 |
+
*/
|
87 |
+
function fs_asset_url( $asset_abs_path ) {
|
88 |
+
$wp_content_dir = fs_normalize_path( WP_CONTENT_DIR );
|
89 |
+
$asset_abs_path = fs_normalize_path( $asset_abs_path );
|
90 |
+
|
91 |
+
if ( 0 === strpos( $asset_abs_path, $wp_content_dir ) ) {
|
92 |
+
// Handle both theme and plugin assets located in the standard directories.
|
93 |
+
$asset_rel_path = str_replace( $wp_content_dir, '', $asset_abs_path );
|
94 |
+
$asset_url = content_url( fs_normalize_path( $asset_rel_path ) );
|
95 |
+
} else {
|
96 |
+
$wp_plugins_dir = fs_normalize_path( WP_PLUGIN_DIR );
|
97 |
+
if ( 0 === strpos( $asset_abs_path, $wp_plugins_dir ) ) {
|
98 |
+
// Try to handle plugin assets that may be located in a non-standard plugins directory.
|
99 |
+
$asset_rel_path = str_replace( $wp_plugins_dir, '', $asset_abs_path );
|
100 |
+
$asset_url = plugins_url( fs_normalize_path( $asset_rel_path ) );
|
101 |
+
} else {
|
102 |
+
// Try to handle theme assets that may be located in a non-standard themes directory.
|
103 |
+
$active_theme_stylesheet = get_stylesheet();
|
104 |
+
$wp_themes_dir = fs_normalize_path( trailingslashit( get_theme_root( $active_theme_stylesheet ) ) );
|
105 |
+
$asset_rel_path = str_replace( $wp_themes_dir, '', fs_normalize_path( $asset_abs_path ) );
|
106 |
+
$asset_url = trailingslashit( get_theme_root_uri( $active_theme_stylesheet ) ) . fs_normalize_path( $asset_rel_path );
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
return $asset_url;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
if ( ! function_exists( 'fs_enqueue_local_style' ) ) {
|
115 |
+
function fs_enqueue_local_style( $handle, $path, $deps = array(), $ver = false, $media = 'all' ) {
|
116 |
+
wp_enqueue_style( $handle, fs_asset_url( WP_FS__DIR_CSS . '/' . trim( $path, '/' ) ), $deps, $ver, $media );
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
if ( ! function_exists( 'fs_enqueue_local_script' ) ) {
|
121 |
+
function fs_enqueue_local_script( $handle, $path, $deps = array(), $ver = false, $in_footer = 'all' ) {
|
122 |
+
wp_enqueue_script( $handle, fs_asset_url( WP_FS__DIR_JS . '/' . trim( $path, '/' ) ), $deps, $ver, $in_footer );
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
if ( ! function_exists( 'fs_img_url' ) ) {
|
127 |
+
function fs_img_url( $path, $img_dir = WP_FS__DIR_IMG ) {
|
128 |
+
return ( fs_asset_url( $img_dir . '/' . trim( $path, '/' ) ) );
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
#--------------------------------------------------------------------------------
|
133 |
+
#region Request handlers.
|
134 |
+
#--------------------------------------------------------------------------------
|
135 |
+
|
136 |
+
if ( ! function_exists( 'fs_request_get' ) ) {
|
137 |
+
/**
|
138 |
+
* A helper method to fetch GET/POST user input with an optional default value when the input is not set.
|
139 |
+
* @author Vova Feldman (@svovaf)
|
140 |
+
*
|
141 |
+
* @param string $key
|
142 |
+
* @param mixed $def
|
143 |
+
* @param string|bool $type Since 1.2.1.7 - when set to 'get' will look for the value passed via querystring, when
|
144 |
+
* set to 'post' will look for the value passed via the POST request's body, otherwise,
|
145 |
+
* will check if the parameter was passed in any of the two.
|
146 |
+
*
|
147 |
+
* @return mixed
|
148 |
+
*/
|
149 |
+
function fs_request_get( $key, $def = false, $type = false ) {
|
150 |
+
if ( is_string( $type ) ) {
|
151 |
+
$type = strtolower( $type );
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Note to WordPress.org Reviewers:
|
156 |
+
* This is a helper method to fetch GET/POST user input with an optional default value when the input is not set. The actual sanitization is done in the scope of the function's usage.
|
157 |
+
*/
|
158 |
+
switch ( $type ) {
|
159 |
+
case 'post':
|
160 |
+
$value = isset( $_POST[ $key ] ) ? $_POST[ $key ] : $def;
|
161 |
+
break;
|
162 |
+
case 'get':
|
163 |
+
$value = isset( $_GET[ $key ] ) ? $_GET[ $key ] : $def;
|
164 |
+
break;
|
165 |
+
default:
|
166 |
+
$value = isset( $_REQUEST[ $key ] ) ? $_REQUEST[ $key ] : $def;
|
167 |
+
break;
|
168 |
+
}
|
169 |
+
|
170 |
+
return $value;
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
if ( ! function_exists( 'fs_request_has' ) ) {
|
175 |
+
function fs_request_has( $key ) {
|
176 |
+
return isset( $_REQUEST[ $key ] );
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
if ( ! function_exists( 'fs_request_get_bool' ) ) {
|
181 |
+
/**
|
182 |
+
* A helper method to fetch GET/POST user boolean input with an optional default value when the input is not set.
|
183 |
+
*
|
184 |
+
* @author Vova Feldman (@svovaf)
|
185 |
+
*
|
186 |
+
* @param string $key
|
187 |
+
* @param bool $def
|
188 |
+
*
|
189 |
+
* @return bool|mixed
|
190 |
+
*/
|
191 |
+
function fs_request_get_bool( $key, $def = false ) {
|
192 |
+
$val = fs_request_get( $key, null );
|
193 |
+
|
194 |
+
if ( is_null( $val ) ) {
|
195 |
+
return $def;
|
196 |
+
}
|
197 |
+
|
198 |
+
if ( is_bool( $val ) ) {
|
199 |
+
return $val;
|
200 |
+
} else if ( is_numeric( $val ) ) {
|
201 |
+
if ( 1 == $val ) {
|
202 |
+
return true;
|
203 |
+
} else if ( 0 == $val ) {
|
204 |
+
return false;
|
205 |
+
}
|
206 |
+
} else if ( is_string( $val ) ) {
|
207 |
+
$val = strtolower( $val );
|
208 |
+
|
209 |
+
if ( 'true' === $val ) {
|
210 |
+
return true;
|
211 |
+
} else if ( 'false' === $val ) {
|
212 |
+
return false;
|
213 |
+
}
|
214 |
+
}
|
215 |
+
|
216 |
+
return $def;
|
217 |
+
}
|
218 |
+
}
|
219 |
+
|
220 |
+
if ( ! function_exists( 'fs_request_is_post' ) ) {
|
221 |
+
function fs_request_is_post() {
|
222 |
+
return ( 'post' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
|
223 |
+
}
|
224 |
+
}
|
225 |
+
|
226 |
+
if ( ! function_exists( 'fs_request_is_get' ) ) {
|
227 |
+
function fs_request_is_get() {
|
228 |
+
return ( 'get' === strtolower( $_SERVER['REQUEST_METHOD'] ) );
|
229 |
+
}
|
230 |
+
}
|
231 |
+
|
232 |
+
if ( ! function_exists( 'fs_get_action' ) ) {
|
233 |
+
function fs_get_action( $action_key = 'action' ) {
|
234 |
+
if ( ! empty( $_REQUEST[ $action_key ] ) && is_string( $_REQUEST[ $action_key ] ) ) {
|
235 |
+
return strtolower( $_REQUEST[ $action_key ] );
|
236 |
+
}
|
237 |
+
|
238 |
+
if ( 'action' == $action_key ) {
|
239 |
+
$action_key = 'fs_action';
|
240 |
+
|
241 |
+
if ( ! empty( $_REQUEST[ $action_key ] ) && is_string( $_REQUEST[ $action_key ] ) ) {
|
242 |
+
return strtolower( $_REQUEST[ $action_key ] );
|
243 |
+
}
|
244 |
+
}
|
245 |
+
|
246 |
+
return false;
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
if ( ! function_exists( 'fs_request_is_action' ) ) {
|
251 |
+
function fs_request_is_action( $action, $action_key = 'action' ) {
|
252 |
+
return ( strtolower( $action ) === fs_get_action( $action_key ) );
|
253 |
+
}
|
254 |
+
}
|
255 |
+
|
256 |
+
if ( ! function_exists( 'fs_request_is_action_secure' ) ) {
|
257 |
+
/**
|
258 |
+
* @author Vova Feldman (@svovaf)
|
259 |
+
* @since 1.0.0
|
260 |
+
*
|
261 |
+
* @since 1.2.1.5 Allow nonce verification.
|
262 |
+
*
|
263 |
+
* @param string $action
|
264 |
+
* @param string $action_key
|
265 |
+
* @param string $nonce_key
|
266 |
+
*
|
267 |
+
* @return bool
|
268 |
+
*/
|
269 |
+
function fs_request_is_action_secure(
|
270 |
+
$action,
|
271 |
+
$action_key = 'action',
|
272 |
+
$nonce_key = 'nonce'
|
273 |
+
) {
|
274 |
+
if ( strtolower( $action ) !== fs_get_action( $action_key ) ) {
|
275 |
+
return false;
|
276 |
+
}
|
277 |
+
|
278 |
+
$nonce = ! empty( $_REQUEST[ $nonce_key ] ) ?
|
279 |
+
$_REQUEST[ $nonce_key ] :
|
280 |
+
'';
|
281 |
+
|
282 |
+
if ( empty( $nonce ) ||
|
283 |
+
( false === wp_verify_nonce( $nonce, $action ) )
|
284 |
+
) {
|
285 |
+
return false;
|
286 |
+
}
|
287 |
+
|
288 |
+
return true;
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
+
#endregion
|
293 |
+
|
294 |
+
if ( ! function_exists( 'fs_is_plugin_page' ) ) {
|
295 |
+
function fs_is_plugin_page( $page_slug ) {
|
296 |
+
return ( is_admin() && $page_slug === fs_request_get( 'page' ) );
|
297 |
+
}
|
298 |
+
}
|
299 |
+
|
300 |
+
if ( ! function_exists( 'fs_get_raw_referer' ) ) {
|
301 |
+
/**
|
302 |
+
* Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
|
303 |
+
*
|
304 |
+
* Do not use for redirects, use {@see wp_get_referer()} instead.
|
305 |
+
*
|
306 |
+
* @since 1.2.3
|
307 |
+
*
|
308 |
+
* @return string|false Referer URL on success, false on failure.
|
309 |
+
*/
|
310 |
+
function fs_get_raw_referer() {
|
311 |
+
if ( function_exists( 'wp_get_raw_referer' ) ) {
|
312 |
+
return wp_get_raw_referer();
|
313 |
+
}
|
314 |
+
if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
|
315 |
+
return wp_unslash( $_REQUEST['_wp_http_referer'] );
|
316 |
+
} else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
|
317 |
+
return wp_unslash( $_SERVER['HTTP_REFERER'] );
|
318 |
+
}
|
319 |
+
|
320 |
+
return false;
|
321 |
+
}
|
322 |
+
}
|
323 |
+
|
324 |
+
/* Core UI.
|
325 |
+
--------------------------------------------------------------------------------------------*/
|
326 |
+
if ( ! function_exists( 'fs_ui_action_button' ) ) {
|
327 |
+
/**
|
328 |
+
* @param number $module_id
|
329 |
+
* @param string $page
|
330 |
+
* @param string $action
|
331 |
+
* @param string $title
|
332 |
+
* @param string $button_class
|
333 |
+
* @param array $params
|
334 |
+
* @param bool $is_primary
|
335 |
+
* @param bool $is_small
|
336 |
+
* @param string|bool $icon_class Optional class for an icon (since 1.1.7).
|
337 |
+
* @param string|bool $confirmation Optional confirmation message before submit (since 1.1.7).
|
338 |
+
* @param string $method Since 1.1.7
|
339 |
+
*
|
340 |
+
* @uses fs_ui_get_action_button()
|
341 |
+
*/
|
342 |
+
function fs_ui_action_button(
|
343 |
+
$module_id,
|
344 |
+
$page,
|
345 |
+
$action,
|
346 |
+
$title,
|
347 |
+
$button_class = '',
|
348 |
+
$params = array(),
|
349 |
+
$is_primary = true,
|
350 |
+
$is_small = false,
|
351 |
+
$icon_class = false,
|
352 |
+
$confirmation = false,
|
353 |
+
$method = 'GET'
|
354 |
+
) {
|
355 |
+
echo fs_ui_get_action_button(
|
356 |
+
$module_id,
|
357 |
+
$page,
|
358 |
+
$action,
|
359 |
+
$title,
|
360 |
+
$button_class,
|
361 |
+
$params,
|
362 |
+
$is_primary,
|
363 |
+
$is_small,
|
364 |
+
$icon_class,
|
365 |
+
$confirmation,
|
366 |
+
$method
|
367 |
+
);
|
368 |
+
}
|
369 |
+
}
|
370 |
+
|
371 |
+
if ( ! function_exists( 'fs_ui_get_action_button' ) ) {
|
372 |
+
/**
|
373 |
+
* @author Vova Feldman (@svovaf)
|
374 |
+
* @since 1.1.7
|
375 |
+
*
|
376 |
+
* @param number $module_id
|
377 |
+
* @param string $page
|
378 |
+
* @param string $action
|
379 |
+
* @param string $title
|
380 |
+
* @param string $button_class
|
381 |
+
* @param array $params
|
382 |
+
* @param bool $is_primary
|
383 |
+
* @param bool $is_small
|
384 |
+
* @param string|bool $icon_class Optional class for an icon.
|
385 |
+
* @param string|bool $confirmation Optional confirmation message before submit.
|
386 |
+
* @param string $method
|
387 |
+
*
|
388 |
+
* @return string
|
389 |
+
*/
|
390 |
+
function fs_ui_get_action_button(
|
391 |
+
$module_id,
|
392 |
+
$page,
|
393 |
+
$action,
|
394 |
+
$title,
|
395 |
+
$button_class = '',
|
396 |
+
$params = array(),
|
397 |
+
$is_primary = true,
|
398 |
+
$is_small = false,
|
399 |
+
$icon_class = false,
|
400 |
+
$confirmation = false,
|
401 |
+
$method = 'GET'
|
402 |
+
) {
|
403 |
+
// Prepend icon (if set).
|
404 |
+
$title = ( is_string( $icon_class ) ? '<i class="' . $icon_class . '"></i> ' : '' ) . $title;
|
405 |
+
|
406 |
+
if ( is_string( $confirmation ) ) {
|
407 |
+
return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="if (confirm(\'%s\')) this.parentNode.submit(); return false;">%s</a></form>',
|
408 |
+
freemius( $module_id )->_get_admin_page_url( $page, $params ),
|
409 |
+
$method,
|
410 |
+
$action,
|
411 |
+
wp_nonce_field( $action, '_wpnonce', true, false ),
|
412 |
+
'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
|
413 |
+
$confirmation,
|
414 |
+
$title
|
415 |
+
);
|
416 |
+
} else if ( 'GET' !== strtoupper( $method ) ) {
|
417 |
+
return sprintf( '<form action="%s" method="%s"><input type="hidden" name="fs_action" value="%s">%s<a href="#" class="%s" onclick="this.parentNode.submit(); return false;">%s</a></form>',
|
418 |
+
freemius( $module_id )->_get_admin_page_url( $page, $params ),
|
419 |
+
$method,
|
420 |
+
$action,
|
421 |
+
wp_nonce_field( $action, '_wpnonce', true, false ),
|
422 |
+
'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
|
423 |
+
$title
|
424 |
+
);
|
425 |
+
} else {
|
426 |
+
return sprintf( '<a href="%s" class="%s">%s</a></form>',
|
427 |
+
wp_nonce_url( freemius( $module_id )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ),
|
428 |
+
'button' . ( ! empty( $button_class ) ? ' ' . $button_class : '' ) . ( $is_primary ? ' button-primary' : '' ) . ( $is_small ? ' button-small' : '' ),
|
429 |
+
$title
|
430 |
+
);
|
431 |
+
}
|
432 |
+
}
|
433 |
+
|
434 |
+
function fs_ui_action_link( $module_id, $page, $action, $title, $params = array() ) {
|
435 |
+
?><a class=""
|
436 |
+
href="<?php echo wp_nonce_url( freemius( $module_id )->_get_admin_page_url( $page, array_merge( $params, array( 'fs_action' => $action ) ) ), $action ) ?>"><?php echo $title ?></a><?php
|
437 |
+
}
|
438 |
+
}
|
439 |
+
|
440 |
+
if ( ! function_exists( 'fs_get_entity' ) ) {
|
441 |
+
/**
|
442 |
+
* @author Leo Fajardo (@leorw)
|
443 |
+
* @since 2.3.1
|
444 |
+
*
|
445 |
+
* @param mixed $entity
|
446 |
+
* @param string $class
|
447 |
+
*
|
448 |
+
* @return FS_Plugin|FS_User|FS_Site|FS_Plugin_License|FS_Plugin_Plan|FS_Plugin_Tag|FS_Subscription
|
449 |
+
*/
|
450 |
+
function fs_get_entity( $entity, $class ) {
|
451 |
+
if ( ! is_object( $entity ) || $entity instanceof $class ) {
|
452 |
+
return $entity;
|
453 |
+
}
|
454 |
+
|
455 |
+
return new $class( $entity );
|
456 |
+
}
|
457 |
+
}
|
458 |
+
|
459 |
+
if ( ! function_exists( 'fs_get_entities' ) ) {
|
460 |
+
/**
|
461 |
+
* @author Leo Fajardo (@leorw)
|
462 |
+
* @since 2.3.1
|
463 |
+
*
|
464 |
+
* @param mixed $entities
|
465 |
+
* @param string $class_name
|
466 |
+
*
|
467 |
+
* @return FS_Plugin[]|FS_User[]|FS_Site[]|FS_Plugin_License[]|FS_Plugin_Plan[]|FS_Plugin_Tag[]|FS_Subscription[]
|
468 |
+
*/
|
469 |
+
function fs_get_entities( $entities, $class_name ) {
|
470 |
+
if ( ! is_array( $entities ) || empty( $entities ) ) {
|
471 |
+
return $entities;
|
472 |
+
}
|
473 |
+
|
474 |
+
// Get first element.
|
475 |
+
$first_array_element = reset( $entities );
|
476 |
+
|
477 |
+
if ( $first_array_element instanceof $class_name ) {
|
478 |
+
/**
|
479 |
+
* If the first element of the array is an instance of the context class, assume that all other
|
480 |
+
* elements are instances of the class.
|
481 |
+
*/
|
482 |
+
return $entities;
|
483 |
+
}
|
484 |
+
|
485 |
+
if (
|
486 |
+
is_array( $first_array_element ) &&
|
487 |
+
! empty( $first_array_element )
|
488 |
+
) {
|
489 |
+
$first_array_element = reset( $first_array_element );
|
490 |
+
|
491 |
+
if ( $first_array_element instanceof $class_name ) {
|
492 |
+
/**
|
493 |
+
* If the first element of the `$entities` array is an array whose first element is an instance of the
|
494 |
+
* context class, assume that all other objects are instances of the class.
|
495 |
+
*/
|
496 |
+
return $entities;
|
497 |
+
}
|
498 |
+
}
|
499 |
+
|
500 |
+
foreach ( $entities as $key => $entities_or_entity ) {
|
501 |
+
if ( is_array( $entities_or_entity ) ) {
|
502 |
+
$entities[ $key ] = fs_get_entities( $entities_or_entity, $class_name );
|
503 |
+
} else {
|
504 |
+
$entities[ $key ] = fs_get_entity( $entities_or_entity, $class_name );
|
505 |
+
}
|
506 |
+
}
|
507 |
+
|
508 |
+
return $entities;
|
509 |
+
}
|
510 |
+
}
|
511 |
+
|
512 |
+
if ( ! function_exists( 'fs_nonce_url' ) ) {
|
513 |
+
/**
|
514 |
+
* Retrieve URL with nonce added to URL query.
|
515 |
+
*
|
516 |
+
* Originally was using `wp_nonce_url()` but the new version
|
517 |
+
* changed the return value to escaped URL, that's not the expected
|
518 |
+
* behaviour.
|
519 |
+
*
|
520 |
+
* @author Vova Feldman (@svovaf)
|
521 |
+
* @since ~1.1.3
|
522 |
+
*
|
523 |
+
* @param string $actionurl URL to add nonce action.
|
524 |
+
* @param int|string $action Optional. Nonce action name. Default -1.
|
525 |
+
* @param string $name Optional. Nonce name. Default '_wpnonce'.
|
526 |
+
*
|
527 |
+
* @return string Escaped URL with nonce action added.
|
528 |
+
*/
|
529 |
+
function fs_nonce_url( $actionurl, $action = - 1, $name = '_wpnonce' ) {
|
530 |
+
return add_query_arg( $name, wp_create_nonce( $action ), $actionurl );
|
531 |
+
}
|
532 |
+
}
|
533 |
+
|
534 |
+
if ( ! function_exists( 'fs_starts_with' ) ) {
|
535 |
+
/**
|
536 |
+
* Check if string starts with.
|
537 |
+
*
|
538 |
+
* @author Vova Feldman (@svovaf)
|
539 |
+
* @since 1.1.3
|
540 |
+
*
|
541 |
+
* @param string $haystack
|
542 |
+
* @param string $needle
|
543 |
+
*
|
544 |
+
* @return bool
|
545 |
+
*/
|
546 |
+
function fs_starts_with( $haystack, $needle ) {
|
547 |
+
$length = strlen( $needle );
|
548 |
+
|
549 |
+
return ( substr( $haystack, 0, $length ) === $needle );
|
550 |
+
}
|
551 |
+
}
|
552 |
+
|
553 |
+
if ( ! function_exists( 'fs_ends_with' ) ) {
|
554 |
+
/**
|
555 |
+
* Check if string ends with.
|
556 |
+
*
|
557 |
+
* @author Vova Feldman (@svovaf)
|
558 |
+
* @since 2.0.0
|
559 |
+
*
|
560 |
+
* @param string $haystack
|
561 |
+
* @param string $needle
|
562 |
+
*
|
563 |
+
* @return bool
|
564 |
+
*/
|
565 |
+
function fs_ends_with( $haystack, $needle ) {
|
566 |
+
$length = strlen( $needle );
|
567 |
+
$start = $length * - 1; // negative
|
568 |
+
|
569 |
+
return ( substr( $haystack, $start ) === $needle );
|
570 |
+
}
|
571 |
+
}
|
572 |
+
|
573 |
+
if ( ! function_exists( 'fs_strip_url_protocol' ) ) {
|
574 |
+
function fs_strip_url_protocol( $url ) {
|
575 |
+
if ( ! fs_starts_with( $url, 'http' ) ) {
|
576 |
+
return $url;
|
577 |
+
}
|
578 |
+
|
579 |
+
$protocol_pos = strpos( $url, '://' );
|
580 |
+
|
581 |
+
if ( $protocol_pos > 5 ) {
|
582 |
+
return $url;
|
583 |
+
}
|
584 |
+
|
585 |
+
return substr( $url, $protocol_pos + 3 );
|
586 |
+
}
|
587 |
+
}
|
588 |
+
|
589 |
+
#region Url Canonization ------------------------------------------------------------------
|
590 |
+
|
591 |
+
if ( ! function_exists( 'fs_canonize_url' ) ) {
|
592 |
+
/**
|
593 |
+
* @author Vova Feldman (@svovaf)
|
594 |
+
* @since 1.1.3
|
595 |
+
*
|
596 |
+
* @param string $url
|
597 |
+
* @param bool $omit_host
|
598 |
+
* @param array $ignore_params
|
599 |
+
*
|
600 |
+
* @return string
|
601 |
+
*/
|
602 |
+
function fs_canonize_url( $url, $omit_host = false, $ignore_params = array() ) {
|
603 |
+
$parsed_url = parse_url( strtolower( $url ) );
|
604 |
+
|
605 |
+
// if ( ! isset( $parsed_url['host'] ) ) {
|
606 |
+
// return $url;
|
607 |
+
// }
|
608 |
+
|
609 |
+
$canonical = ( ( $omit_host || ! isset( $parsed_url['host'] ) ) ? '' : $parsed_url['host'] ) . $parsed_url['path'];
|
610 |
+
|
611 |
+
if ( isset( $parsed_url['query'] ) ) {
|
612 |
+
parse_str( $parsed_url['query'], $queryString );
|
613 |
+
$canonical .= '?' . fs_canonize_query_string( $queryString, $ignore_params );
|
614 |
+
}
|
615 |
+
|
616 |
+
return $canonical;
|
617 |
+
}
|
618 |
+
}
|
619 |
+
|
620 |
+
if ( ! function_exists( 'fs_canonize_query_string' ) ) {
|
621 |
+
/**
|
622 |
+
* @author Vova Feldman (@svovaf)
|
623 |
+
* @since 1.1.3
|
624 |
+
*
|
625 |
+
* @param array $params
|
626 |
+
* @param array $ignore_params
|
627 |
+
* @param bool $params_prefix
|
628 |
+
*
|
629 |
+
* @return string
|
630 |
+
*/
|
631 |
+
function fs_canonize_query_string( array $params, array &$ignore_params, $params_prefix = false ) {
|
632 |
+
if ( ! is_array( $params ) || 0 === count( $params ) ) {
|
633 |
+
return '';
|
634 |
+
}
|
635 |
+
|
636 |
+
// Url encode both keys and values
|
637 |
+
$keys = fs_urlencode_rfc3986( array_keys( $params ) );
|
638 |
+
$values = fs_urlencode_rfc3986( array_values( $params ) );
|
639 |
+
$params = array_combine( $keys, $values );
|
640 |
+
|
641 |
+
// Parameters are sorted by name, using lexicographical byte value ordering.
|
642 |
+
// Ref: Spec: 9.1.1 (1)
|
643 |
+
uksort( $params, 'strcmp' );
|
644 |
+
|
645 |
+
$pairs = array();
|
646 |
+
foreach ( $params as $parameter => $value ) {
|
647 |
+
$lower_param = strtolower( $parameter );
|
648 |
+
|
649 |
+
// Skip ignore params.
|
650 |
+
if ( in_array( $lower_param, $ignore_params ) ||
|
651 |
+
( false !== $params_prefix && fs_starts_with( $lower_param, $params_prefix ) )
|
652 |
+
) {
|
653 |
+
continue;
|
654 |
+
}
|
655 |
+
|
656 |
+
if ( is_array( $value ) ) {
|
657 |
+
// If two or more parameters share the same name, they are sorted by their value
|
658 |
+
// Ref: Spec: 9.1.1 (1)
|
659 |
+
natsort( $value );
|
660 |
+
foreach ( $value as $duplicate_value ) {
|
661 |
+
$pairs[] = $lower_param . '=' . $duplicate_value;
|
662 |
+
}
|
663 |
+
} else {
|
664 |
+
$pairs[] = $lower_param . '=' . $value;
|
665 |
+
}
|
666 |
+
}
|
667 |
+
|
668 |
+
if ( 0 === count( $pairs ) ) {
|
669 |
+
return '';
|
670 |
+
}
|
671 |
+
|
672 |
+
return implode( "&", $pairs );
|
673 |
+
}
|
674 |
+
}
|
675 |
+
|
676 |
+
if ( ! function_exists( 'fs_urlencode_rfc3986' ) ) {
|
677 |
+
/**
|
678 |
+
* @author Vova Feldman (@svovaf)
|
679 |
+
* @since 1.1.3
|
680 |
+
*
|
681 |
+
* @param string|string[] $input
|
682 |
+
*
|
683 |
+
* @return array|mixed|string
|
684 |
+
*/
|
685 |
+
function fs_urlencode_rfc3986( $input ) {
|
686 |
+
if ( is_array( $input ) ) {
|
687 |
+
return array_map( 'fs_urlencode_rfc3986', $input );
|
688 |
+
} else if ( is_scalar( $input ) ) {
|
689 |
+
return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
|
690 |
+
}
|
691 |
+
|
692 |
+
return '';
|
693 |
+
}
|
694 |
+
}
|
695 |
+
|
696 |
+
#endregion Url Canonization ------------------------------------------------------------------
|
697 |
+
|
698 |
+
if ( ! function_exists( 'fs_download_image' ) ) {
|
699 |
+
/**
|
700 |
+
* @author Vova Feldman (@svovaf)
|
701 |
+
*
|
702 |
+
* @since 1.2.2 Changed to usage of WP_Filesystem_Direct.
|
703 |
+
*
|
704 |
+
* @param string $from URL
|
705 |
+
* @param string $to File path.
|
706 |
+
*
|
707 |
+
* @return bool Is successfully downloaded.
|
708 |
+
*/
|
709 |
+
function fs_download_image( $from, $to ) {
|
710 |
+
$dir = dirname( $to );
|
711 |
+
|
712 |
+
if ( 'direct' !== get_filesystem_method( array(), $dir ) ) {
|
713 |
+
return false;
|
714 |
+
}
|
715 |
+
|
716 |
+
if ( ! class_exists( 'WP_Filesystem_Direct' ) ) {
|
717 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
|
718 |
+
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
|
719 |
+
}
|
720 |
+
|
721 |
+
$fs = new WP_Filesystem_Direct( '' );
|
722 |
+
$tmpfile = download_url( $from );
|
723 |
+
|
724 |
+
if ( $tmpfile instanceof WP_Error ) {
|
725 |
+
// Issue downloading the file.
|
726 |
+
return false;
|
727 |
+
}
|
728 |
+
|
729 |
+
$fs->copy( $tmpfile, $to );
|
730 |
+
$fs->delete( $tmpfile );
|
731 |
+
|
732 |
+
return true;
|
733 |
+
}
|
734 |
+
}
|
735 |
+
|
736 |
+
/* General Utilities
|
737 |
+
--------------------------------------------------------------------------------------------*/
|
738 |
+
|
739 |
+
if ( ! function_exists( 'fs_sort_by_priority' ) ) {
|
740 |
+
/**
|
741 |
+
* Sorts an array by the value of the priority key.
|
742 |
+
*
|
743 |
+
* @author Daniel Iser (@danieliser)
|
744 |
+
* @since 1.1.7
|
745 |
+
*
|
746 |
+
* @param $a
|
747 |
+
* @param $b
|
748 |
+
*
|
749 |
+
* @return int
|
750 |
+
*/
|
751 |
+
function fs_sort_by_priority( $a, $b ) {
|
752 |
+
|
753 |
+
// If b has a priority and a does not, b wins.
|
754 |
+
if ( ! isset( $a['priority'] ) && isset( $b['priority'] ) ) {
|
755 |
+
return 1;
|
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 |
+
}
|
763 |
+
|
764 |
+
// If both have priority return the winner.
|
765 |
+
return ( $a['priority'] < $b['priority'] ) ? - 1 : 1;
|
766 |
+
}
|
767 |
+
}
|
768 |
+
|
769 |
+
#--------------------------------------------------------------------------------
|
770 |
+
#region Localization
|
771 |
+
#--------------------------------------------------------------------------------
|
772 |
+
|
773 |
+
if ( ! function_exists( 'fs_text' ) ) {
|
774 |
+
/**
|
775 |
+
* Retrieve a translated text by key.
|
776 |
+
*
|
777 |
+
* @author Vova Feldman (@svovaf)
|
778 |
+
* @since 1.2.1.7
|
779 |
+
*
|
780 |
+
* @param string $key
|
781 |
+
* @param string $slug
|
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 ] ) ) {
|
794 |
+
return $fs_text_overrides[ $slug ][ $key ];
|
795 |
+
}
|
796 |
+
|
797 |
+
$lower_key = strtolower( $key );
|
798 |
+
if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
|
799 |
+
return $fs_text_overrides[ $slug ][ $lower_key ];
|
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 |
+
|
822 |
+
#region Private
|
823 |
+
|
824 |
+
/**
|
825 |
+
* Retrieve an inline translated text by key with a context.
|
826 |
+
*
|
827 |
+
* @author Vova Feldman (@svovaf)
|
828 |
+
* @since 1.2.3
|
829 |
+
*
|
830 |
+
* @param string $text Translatable string.
|
831 |
+
* @param string $context Context information for the translators.
|
832 |
+
* @param string $key String key for overrides.
|
833 |
+
* @param string $slug Module slug for overrides.
|
834 |
+
*
|
835 |
+
* @return string
|
836 |
+
*
|
837 |
+
* @global $fs_text_overrides
|
838 |
+
*/
|
839 |
+
function _fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
840 |
+
list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
|
841 |
+
|
842 |
+
// Avoid misleading Theme Check warning.
|
843 |
+
$fn = 'translate_with_gettext_context';
|
844 |
+
|
845 |
+
return $fn( $text, $context, $text_domain );
|
846 |
+
}
|
847 |
+
|
848 |
+
#endregion
|
849 |
+
|
850 |
+
/**
|
851 |
+
* Retrieve an inline translated text by key with a context.
|
852 |
+
*
|
853 |
+
* @author Vova Feldman (@svovaf)
|
854 |
+
* @since 1.2.3
|
855 |
+
*
|
856 |
+
* @param string $text Translatable string.
|
857 |
+
* @param string $context Context information for the translators.
|
858 |
+
* @param string $key String key for overrides.
|
859 |
+
* @param string $slug Module slug for overrides.
|
860 |
+
*
|
861 |
+
* @return string
|
862 |
+
*
|
863 |
+
* @global $fs_text_overrides
|
864 |
+
*/
|
865 |
+
function fs_text_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
866 |
+
return _fs_text_x_inline( $text, $context, $key, $slug );
|
867 |
+
}
|
868 |
+
|
869 |
+
/**
|
870 |
+
* Output a translated text by key.
|
871 |
+
*
|
872 |
+
* @author Vova Feldman (@svovaf)
|
873 |
+
* @since 1.2.1.7
|
874 |
+
*
|
875 |
+
* @param string $key
|
876 |
+
* @param string $slug
|
877 |
+
*/
|
878 |
+
function fs_echo( $key, $slug = 'freemius' ) {
|
879 |
+
echo fs_text( $key, $slug );
|
880 |
+
}
|
881 |
+
|
882 |
+
/**
|
883 |
+
* Output an inline translated text.
|
884 |
+
*
|
885 |
+
* @author Vova Feldman (@svovaf)
|
886 |
+
* @since 1.2.3
|
887 |
+
*
|
888 |
+
* @param string $text Translatable string.
|
889 |
+
* @param string $key String key for overrides.
|
890 |
+
* @param string $slug Module slug for overrides.
|
891 |
+
*/
|
892 |
+
function fs_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
893 |
+
echo _fs_text_inline( $text, $key, $slug );
|
894 |
+
}
|
895 |
+
|
896 |
+
/**
|
897 |
+
* Output an inline translated text with a context.
|
898 |
+
*
|
899 |
+
* @author Vova Feldman (@svovaf)
|
900 |
+
* @since 1.2.3
|
901 |
+
*
|
902 |
+
* @param string $text Translatable string.
|
903 |
+
* @param string $context Context information for the translators.
|
904 |
+
* @param string $key String key for overrides.
|
905 |
+
* @param string $slug Module slug for overrides.
|
906 |
+
*/
|
907 |
+
function fs_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
908 |
+
echo _fs_text_x_inline( $text, $context, $key, $slug );
|
909 |
+
}
|
910 |
+
}
|
911 |
+
|
912 |
+
if ( ! function_exists( 'fs_text_override' ) ) {
|
913 |
+
/**
|
914 |
+
* Get a translatable text override if exists, or `false`.
|
915 |
+
*
|
916 |
+
* @author Vova Feldman (@svovaf)
|
917 |
+
* @since 1.2.1.7
|
918 |
+
*
|
919 |
+
* @param string $text Translatable string.
|
920 |
+
* @param string $key String key for overrides.
|
921 |
+
* @param string $slug Module slug for overrides.
|
922 |
+
*
|
923 |
+
* @return string|false
|
924 |
+
*/
|
925 |
+
function fs_text_override( $text, $key, $slug ) {
|
926 |
+
global $fs_text_overrides;
|
927 |
+
|
928 |
+
/**
|
929 |
+
* Check if string is overridden.
|
930 |
+
*/
|
931 |
+
if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
|
932 |
+
return false;
|
933 |
+
}
|
934 |
+
|
935 |
+
if ( empty( $key ) ) {
|
936 |
+
$key = strtolower( str_replace( ' ', '-', $text ) );
|
937 |
+
}
|
938 |
+
|
939 |
+
if ( isset( $fs_text_overrides[ $slug ][ $key ] ) ) {
|
940 |
+
return $fs_text_overrides[ $slug ][ $key ];
|
941 |
+
}
|
942 |
+
|
943 |
+
$lower_key = strtolower( $key );
|
944 |
+
if ( isset( $fs_text_overrides[ $slug ][ $lower_key ] ) ) {
|
945 |
+
return $fs_text_overrides[ $slug ][ $lower_key ];
|
946 |
+
}
|
947 |
+
|
948 |
+
return false;
|
949 |
+
}
|
950 |
+
}
|
951 |
+
|
952 |
+
if ( ! function_exists( 'fs_text_and_domain' ) ) {
|
953 |
+
/**
|
954 |
+
* Get a translatable text and its text domain.
|
955 |
+
*
|
956 |
+
* When the text is overridden by the module, returns the overridden text and the text domain of the module. Otherwise, returns the original text and 'freemius' as the text domain.
|
957 |
+
*
|
958 |
+
* @author Vova Feldman (@svovaf)
|
959 |
+
* @since 1.2.1.7
|
960 |
+
*
|
961 |
+
* @param string $text Translatable string.
|
962 |
+
* @param string $key String key for overrides.
|
963 |
+
* @param string $slug Module slug for overrides.
|
964 |
+
*
|
965 |
+
* @return string[]
|
966 |
+
*/
|
967 |
+
function fs_text_and_domain( $text, $key, $slug ) {
|
968 |
+
$override = fs_text_override( $text, $key, $slug );
|
969 |
+
|
970 |
+
if ( false === $override ) {
|
971 |
+
// No override, use FS text domain.
|
972 |
+
$text_domain = 'freemius';
|
973 |
+
} else {
|
974 |
+
// Found an override.
|
975 |
+
$text = $override;
|
976 |
+
// Use the module's text domain.
|
977 |
+
$text_domain = $slug;
|
978 |
+
}
|
979 |
+
|
980 |
+
return array( $text, $text_domain );
|
981 |
+
}
|
982 |
+
}
|
983 |
+
|
984 |
+
if ( ! function_exists( '_fs_text_inline' ) ) {
|
985 |
+
/**
|
986 |
+
* Retrieve an inline translated text by key.
|
987 |
+
*
|
988 |
+
* @author Vova Feldman (@svovaf)
|
989 |
+
* @since 1.2.3
|
990 |
+
*
|
991 |
+
* @param string $text Translatable string.
|
992 |
+
* @param string $key String key for overrides.
|
993 |
+
* @param string $slug Module slug for overrides.
|
994 |
+
*
|
995 |
+
* @return string
|
996 |
+
*
|
997 |
+
* @global $fs_text_overrides
|
998 |
+
*/
|
999 |
+
function _fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
|
1000 |
+
list( $text, $text_domain ) = fs_text_and_domain( $text, $key, $slug );
|
1001 |
+
|
1002 |
+
// Avoid misleading Theme Check warning.
|
1003 |
+
$fn = 'translate';
|
1004 |
+
|
1005 |
+
return $fn( $text, $text_domain );
|
1006 |
+
}
|
1007 |
+
}
|
1008 |
+
|
1009 |
+
if ( ! function_exists( 'fs_text_inline' ) ) {
|
1010 |
+
/**
|
1011 |
+
* Retrieve an inline translated text by key.
|
1012 |
+
*
|
1013 |
+
* @author Vova Feldman (@svovaf)
|
1014 |
+
* @since 1.2.3
|
1015 |
+
*
|
1016 |
+
* @param string $text Translatable string.
|
1017 |
+
* @param string $key String key for overrides.
|
1018 |
+
* @param string $slug Module slug for overrides.
|
1019 |
+
*
|
1020 |
+
* @return string
|
1021 |
+
*
|
1022 |
+
* @global $fs_text_overrides
|
1023 |
+
*/
|
1024 |
+
function fs_text_inline( $text, $key = '', $slug = 'freemius' ) {
|
1025 |
+
return _fs_text_inline( $text, $key, $slug );
|
1026 |
+
}
|
1027 |
+
}
|
1028 |
+
|
1029 |
+
if ( ! function_exists( 'fs_esc_attr' ) ) {
|
1030 |
+
/**
|
1031 |
+
* @author Vova Feldman
|
1032 |
+
* @since 1.2.1.6
|
1033 |
+
*
|
1034 |
+
* @param string $key
|
1035 |
+
* @param string $slug
|
1036 |
+
*
|
1037 |
+
* @return string
|
1038 |
+
*/
|
1039 |
+
function fs_esc_attr( $key, $slug ) {
|
1040 |
+
return esc_attr( fs_text( $key, $slug ) );
|
1041 |
+
}
|
1042 |
+
}
|
1043 |
+
|
1044 |
+
if ( ! function_exists( 'fs_esc_attr_inline' ) ) {
|
1045 |
+
/**
|
1046 |
+
* @author Vova Feldman (@svovaf)
|
1047 |
+
* @since 1.2.3
|
1048 |
+
*
|
1049 |
+
* @param string $text Translatable string.
|
1050 |
+
* @param string $key String key for overrides.
|
1051 |
+
* @param string $slug Module slug for overrides.
|
1052 |
+
*
|
1053 |
+
* @return string
|
1054 |
+
*/
|
1055 |
+
function fs_esc_attr_inline( $text, $key = '', $slug = 'freemius' ) {
|
1056 |
+
return esc_attr( _fs_text_inline( $text, $key, $slug ) );
|
1057 |
+
}
|
1058 |
+
}
|
1059 |
+
|
1060 |
+
if ( ! function_exists( 'fs_esc_attr_x_inline' ) ) {
|
1061 |
+
/**
|
1062 |
+
* @author Vova Feldman (@svovaf)
|
1063 |
+
* @since 1.2.3
|
1064 |
+
*
|
1065 |
+
* @param string $text Translatable string.
|
1066 |
+
* @param string $context Context information for the translators.
|
1067 |
+
* @param string $key String key for overrides.
|
1068 |
+
* @param string $slug Module slug for overrides.
|
1069 |
+
*
|
1070 |
+
* @return string
|
1071 |
+
*/
|
1072 |
+
function fs_esc_attr_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1073 |
+
return esc_attr( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1074 |
+
}
|
1075 |
+
}
|
1076 |
+
|
1077 |
+
if ( ! function_exists( 'fs_esc_attr_echo' ) ) {
|
1078 |
+
/**
|
1079 |
+
* @author Vova Feldman
|
1080 |
+
* @since 1.2.1.6
|
1081 |
+
*
|
1082 |
+
* @param string $key
|
1083 |
+
* @param string $slug
|
1084 |
+
*/
|
1085 |
+
function fs_esc_attr_echo( $key, $slug ) {
|
1086 |
+
echo esc_attr( fs_text( $key, $slug ) );
|
1087 |
+
}
|
1088 |
+
}
|
1089 |
+
|
1090 |
+
if ( ! function_exists( 'fs_esc_attr_echo_inline' ) ) {
|
1091 |
+
/**
|
1092 |
+
* @author Vova Feldman (@svovaf)
|
1093 |
+
* @since 1.2.3
|
1094 |
+
*
|
1095 |
+
* @param string $text Translatable string.
|
1096 |
+
* @param string $key String key for overrides.
|
1097 |
+
* @param string $slug Module slug for overrides.
|
1098 |
+
*/
|
1099 |
+
function fs_esc_attr_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1100 |
+
echo esc_attr( _fs_text_inline( $text, $key, $slug ) );
|
1101 |
+
}
|
1102 |
+
}
|
1103 |
+
|
1104 |
+
if ( ! function_exists( 'fs_esc_js' ) ) {
|
1105 |
+
/**
|
1106 |
+
* @author Vova Feldman
|
1107 |
+
* @since 1.2.1.6
|
1108 |
+
*
|
1109 |
+
* @param string $key
|
1110 |
+
* @param string $slug
|
1111 |
+
*
|
1112 |
+
* @return string
|
1113 |
+
*/
|
1114 |
+
function fs_esc_js( $key, $slug ) {
|
1115 |
+
return esc_js( fs_text( $key, $slug ) );
|
1116 |
+
}
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
if ( ! function_exists( 'fs_esc_js_inline' ) ) {
|
1120 |
+
/**
|
1121 |
+
* @author Vova Feldman (@svovaf)
|
1122 |
+
* @since 1.2.3
|
1123 |
+
*
|
1124 |
+
* @param string $text Translatable string.
|
1125 |
+
* @param string $key String key for overrides.
|
1126 |
+
* @param string $slug Module slug for overrides.
|
1127 |
+
*
|
1128 |
+
* @return string
|
1129 |
+
*/
|
1130 |
+
function fs_esc_js_inline( $text, $key = '', $slug = 'freemius' ) {
|
1131 |
+
return esc_js( _fs_text_inline( $text, $key, $slug ) );
|
1132 |
+
}
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
if ( ! function_exists( 'fs_esc_js_x_inline' ) ) {
|
1136 |
+
/**
|
1137 |
+
* @author Vova Feldman (@svovaf)
|
1138 |
+
* @since 1.2.3
|
1139 |
+
*
|
1140 |
+
* @param string $text Translatable string.
|
1141 |
+
* @param string $context Context information for the translators.
|
1142 |
+
* @param string $key String key for overrides.
|
1143 |
+
* @param string $slug Module slug for overrides.
|
1144 |
+
*
|
1145 |
+
* @return string
|
1146 |
+
*/
|
1147 |
+
function fs_esc_js_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1148 |
+
return esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1149 |
+
}
|
1150 |
+
}
|
1151 |
+
|
1152 |
+
if ( ! function_exists( 'fs_esc_js_echo_x_inline' ) ) {
|
1153 |
+
/**
|
1154 |
+
* @author Vova Feldman (@svovaf)
|
1155 |
+
* @since 1.2.3
|
1156 |
+
*
|
1157 |
+
* @param string $text Translatable string.
|
1158 |
+
* @param string $context Context information for the translators.
|
1159 |
+
* @param string $key String key for overrides.
|
1160 |
+
* @param string $slug Module slug for overrides.
|
1161 |
+
*
|
1162 |
+
* @return string
|
1163 |
+
*/
|
1164 |
+
function fs_esc_js_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1165 |
+
echo esc_js( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1166 |
+
}
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
if ( ! function_exists( 'fs_esc_js_echo' ) ) {
|
1170 |
+
/**
|
1171 |
+
* @author Vova Feldman
|
1172 |
+
* @since 1.2.1.6
|
1173 |
+
*
|
1174 |
+
* @param string $key
|
1175 |
+
* @param string $slug
|
1176 |
+
*/
|
1177 |
+
function fs_esc_js_echo( $key, $slug ) {
|
1178 |
+
echo esc_js( fs_text( $key, $slug ) );
|
1179 |
+
}
|
1180 |
+
}
|
1181 |
+
|
1182 |
+
if ( ! function_exists( 'fs_esc_js_echo_inline' ) ) {
|
1183 |
+
/**
|
1184 |
+
* @author Vova Feldman (@svovaf)
|
1185 |
+
* @since 1.2.3
|
1186 |
+
*
|
1187 |
+
* @param string $text Translatable string.
|
1188 |
+
* @param string $key String key for overrides.
|
1189 |
+
* @param string $slug Module slug for overrides.
|
1190 |
+
*/
|
1191 |
+
function fs_esc_js_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1192 |
+
echo esc_js( _fs_text_inline( $text, $key, $slug ) );
|
1193 |
+
}
|
1194 |
+
}
|
1195 |
+
|
1196 |
+
if ( ! function_exists( 'fs_json_encode_echo' ) ) {
|
1197 |
+
/**
|
1198 |
+
* @author Vova Feldman
|
1199 |
+
* @since 1.2.1.6
|
1200 |
+
*
|
1201 |
+
* @param string $key
|
1202 |
+
* @param string $slug
|
1203 |
+
*/
|
1204 |
+
function fs_json_encode_echo( $key, $slug ) {
|
1205 |
+
echo json_encode( fs_text( $key, $slug ) );
|
1206 |
+
}
|
1207 |
+
}
|
1208 |
+
|
1209 |
+
if ( ! function_exists( 'fs_json_encode_echo_inline' ) ) {
|
1210 |
+
/**
|
1211 |
+
* @author Vova Feldman (@svovaf)
|
1212 |
+
* @since 1.2.3
|
1213 |
+
*
|
1214 |
+
* @param string $text Translatable string.
|
1215 |
+
* @param string $key String key for overrides.
|
1216 |
+
* @param string $slug Module slug for overrides.
|
1217 |
+
*/
|
1218 |
+
function fs_json_encode_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1219 |
+
echo json_encode( _fs_text_inline( $text, $key, $slug ) );
|
1220 |
+
}
|
1221 |
+
}
|
1222 |
+
|
1223 |
+
if ( ! function_exists( 'fs_esc_html' ) ) {
|
1224 |
+
/**
|
1225 |
+
* @author Vova Feldman
|
1226 |
+
* @since 1.2.1.6
|
1227 |
+
*
|
1228 |
+
* @param string $key
|
1229 |
+
* @param string $slug
|
1230 |
+
*
|
1231 |
+
* @return string
|
1232 |
+
*/
|
1233 |
+
function fs_esc_html( $key, $slug ) {
|
1234 |
+
return esc_html( fs_text( $key, $slug ) );
|
1235 |
+
}
|
1236 |
+
}
|
1237 |
+
|
1238 |
+
if ( ! function_exists( 'fs_esc_html_inline' ) ) {
|
1239 |
+
/**
|
1240 |
+
* @author Vova Feldman (@svovaf)
|
1241 |
+
* @since 1.2.3
|
1242 |
+
*
|
1243 |
+
* @param string $text Translatable string.
|
1244 |
+
* @param string $key String key for overrides.
|
1245 |
+
* @param string $slug Module slug for overrides.
|
1246 |
+
*
|
1247 |
+
* @return string
|
1248 |
+
*/
|
1249 |
+
function fs_esc_html_inline( $text, $key = '', $slug = 'freemius' ) {
|
1250 |
+
return esc_html( _fs_text_inline( $text, $key, $slug ) );
|
1251 |
+
}
|
1252 |
+
}
|
1253 |
+
|
1254 |
+
if ( ! function_exists( 'fs_esc_html_x_inline' ) ) {
|
1255 |
+
/**
|
1256 |
+
* @author Vova Feldman (@svovaf)
|
1257 |
+
* @since 1.2.3
|
1258 |
+
*
|
1259 |
+
* @param string $text Translatable string.
|
1260 |
+
* @param string $context Context information for the translators.
|
1261 |
+
* @param string $key String key for overrides.
|
1262 |
+
* @param string $slug Module slug for overrides.
|
1263 |
+
*
|
1264 |
+
* @return string
|
1265 |
+
*/
|
1266 |
+
function fs_esc_html_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1267 |
+
return esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1268 |
+
}
|
1269 |
+
}
|
1270 |
+
|
1271 |
+
if ( ! function_exists( 'fs_esc_html_echo_x_inline' ) ) {
|
1272 |
+
/**
|
1273 |
+
* @author Vova Feldman (@svovaf)
|
1274 |
+
* @since 1.2.3
|
1275 |
+
*
|
1276 |
+
* @param string $text Translatable string.
|
1277 |
+
* @param string $context Context information for the translators.
|
1278 |
+
* @param string $key String key for overrides.
|
1279 |
+
* @param string $slug Module slug for overrides.
|
1280 |
+
*/
|
1281 |
+
function fs_esc_html_echo_x_inline( $text, $context, $key = '', $slug = 'freemius' ) {
|
1282 |
+
echo esc_html( _fs_text_x_inline( $text, $context, $key, $slug ) );
|
1283 |
+
}
|
1284 |
+
}
|
1285 |
+
|
1286 |
+
if ( ! function_exists( 'fs_esc_html_echo' ) ) {
|
1287 |
+
/**
|
1288 |
+
* @author Vova Feldman
|
1289 |
+
* @since 1.2.1.6
|
1290 |
+
*
|
1291 |
+
* @param string $key
|
1292 |
+
* @param string $slug
|
1293 |
+
*/
|
1294 |
+
function fs_esc_html_echo( $key, $slug ) {
|
1295 |
+
echo esc_html( fs_text( $key, $slug ) );
|
1296 |
+
}
|
1297 |
+
}
|
1298 |
+
|
1299 |
+
if ( ! function_exists( 'fs_esc_html_echo_inline' ) ) {
|
1300 |
+
/**
|
1301 |
+
* @author Vova Feldman (@svovaf)
|
1302 |
+
* @since 1.2.3
|
1303 |
+
*
|
1304 |
+
* @param string $text Translatable string.
|
1305 |
+
* @param string $key String key for overrides.
|
1306 |
+
* @param string $slug Module slug for overrides.
|
1307 |
+
*/
|
1308 |
+
function fs_esc_html_echo_inline( $text, $key = '', $slug = 'freemius' ) {
|
1309 |
+
echo esc_html( _fs_text_inline( $text, $key, $slug ) );
|
1310 |
+
}
|
1311 |
+
}
|
1312 |
+
|
1313 |
+
if ( ! function_exists( 'fs_override_i18n' ) ) {
|
1314 |
+
/**
|
1315 |
+
* Override default i18n text phrases.
|
1316 |
+
*
|
1317 |
+
* @author Vova Feldman (@svovaf)
|
1318 |
+
* @since 1.1.6
|
1319 |
+
*
|
1320 |
+
* @param array[string]string $key_value
|
1321 |
+
* @param string $slug
|
1322 |
+
*
|
1323 |
+
* @global $fs_text_overrides
|
1324 |
+
*/
|
1325 |
+
function fs_override_i18n( array $key_value, $slug = 'freemius' ) {
|
1326 |
+
global $fs_text_overrides;
|
1327 |
+
|
1328 |
+
if ( ! isset( $fs_text_overrides[ $slug ] ) ) {
|
1329 |
+
$fs_text_overrides[ $slug ] = array();
|
1330 |
+
}
|
1331 |
+
|
1332 |
+
foreach ( $key_value as $key => $value ) {
|
1333 |
+
$fs_text_overrides[ $slug ][ $key ] = $value;
|
1334 |
+
}
|
1335 |
+
}
|
1336 |
+
}
|
1337 |
+
|
1338 |
+
#endregion
|
1339 |
+
|
1340 |
+
#--------------------------------------------------------------------------------
|
1341 |
+
#region Multisite Network
|
1342 |
+
#--------------------------------------------------------------------------------
|
1343 |
+
|
1344 |
+
if ( ! function_exists( 'fs_is_plugin_uninstall' ) ) {
|
1345 |
+
/**
|
1346 |
+
* @author Vova Feldman (@svovaf)
|
1347 |
+
* @since 2.0.0
|
1348 |
+
*/
|
1349 |
+
function fs_is_plugin_uninstall() {
|
1350 |
+
return (
|
1351 |
+
defined( 'WP_UNINSTALL_PLUGIN' ) ||
|
1352 |
+
( 0 < did_action( 'update_option_uninstall_plugins' ) )
|
1353 |
+
);
|
1354 |
+
}
|
1355 |
+
}
|
1356 |
+
|
1357 |
+
if ( ! function_exists( 'fs_is_network_admin' ) ) {
|
1358 |
+
/**
|
1359 |
+
* Unlike is_network_admin(), this one will also work properly when
|
1360 |
+
* the context execution is WP AJAX handler, and during plugin
|
1361 |
+
* uninstall.
|
1362 |
+
*
|
1363 |
+
* @author Vova Feldman (@svovaf)
|
1364 |
+
* @since 2.0.0
|
1365 |
+
*/
|
1366 |
+
function fs_is_network_admin() {
|
1367 |
+
return (
|
1368 |
+
WP_FS__IS_NETWORK_ADMIN ||
|
1369 |
+
( is_multisite() && fs_is_plugin_uninstall() )
|
1370 |
+
);
|
1371 |
+
}
|
1372 |
+
}
|
1373 |
+
|
1374 |
+
if ( ! function_exists( 'fs_is_blog_admin' ) ) {
|
1375 |
+
/**
|
1376 |
+
* Unlike is_blog_admin(), this one will also work properly when
|
1377 |
+
* the context execution is WP AJAX handler, and during plugin
|
1378 |
+
* uninstall.
|
1379 |
+
*
|
1380 |
+
* @author Vova Feldman (@svovaf)
|
1381 |
+
* @since 2.0.0
|
1382 |
+
*/
|
1383 |
+
function fs_is_blog_admin() {
|
1384 |
+
return (
|
1385 |
+
WP_FS__IS_BLOG_ADMIN ||
|
1386 |
+
( ! is_multisite() && fs_is_plugin_uninstall() )
|
1387 |
+
);
|
1388 |
+
}
|
1389 |
+
}
|
1390 |
+
|
1391 |
+
#endregion
|
1392 |
+
|
1393 |
+
if ( ! function_exists( 'fs_apply_filter' ) ) {
|
1394 |
+
/**
|
1395 |
+
* Apply filter for specific plugin.
|
1396 |
+
*
|
1397 |
+
* @author Vova Feldman (@svovaf)
|
1398 |
+
* @since 1.0.9
|
1399 |
+
*
|
1400 |
+
* @param string $module_unique_affix Module's unique affix.
|
1401 |
+
* @param string $tag The name of the filter hook.
|
1402 |
+
* @param mixed $value The value on which the filters hooked to `$tag` are applied on.
|
1403 |
+
*
|
1404 |
+
* @return mixed The filtered value after all hooked functions are applied to it.
|
1405 |
+
*
|
1406 |
+
* @uses apply_filters()
|
1407 |
+
*/
|
1408 |
+
function fs_apply_filter( $module_unique_affix, $tag, $value ) {
|
1409 |
+
$args = func_get_args();
|
1410 |
+
|
1411 |
+
return call_user_func_array( 'apply_filters', array_merge(
|
1412 |
+
array( "fs_{$tag}_{$module_unique_affix}" ),
|
1413 |
+
array_slice( $args, 2 ) )
|
1414 |
+
);
|
1415 |
+
}
|
1416 |
}
|
freemius/includes/fs-essential-functions.php
CHANGED
@@ -1,500 +1,500 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* IMPORTANT:
|
4 |
-
* This file will be loaded based on the order of the plugins/themes load.
|
5 |
-
* If there's a theme and a plugin using Freemius, the plugin's essential
|
6 |
-
* file will always load first.
|
7 |
-
*
|
8 |
-
* @package Freemius
|
9 |
-
* @copyright Copyright (c) 2015, Freemius, Inc.
|
10 |
-
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
|
11 |
-
* @since 1.1.5
|
12 |
-
*/
|
13 |
-
|
14 |
-
if ( ! function_exists( 'fs_normalize_path' ) ) {
|
15 |
-
if ( function_exists( 'wp_normalize_path' ) ) {
|
16 |
-
/**
|
17 |
-
* Normalize a filesystem path.
|
18 |
-
*
|
19 |
-
* Replaces backslashes with forward slashes for Windows systems, and ensures
|
20 |
-
* no duplicate slashes exist.
|
21 |
-
*
|
22 |
-
* @param string $path Path to normalize.
|
23 |
-
*
|
24 |
-
* @return string Normalized path.
|
25 |
-
*/
|
26 |
-
function fs_normalize_path( $path ) {
|
27 |
-
return wp_normalize_path( $path );
|
28 |
-
}
|
29 |
-
} else {
|
30 |
-
function fs_normalize_path( $path ) {
|
31 |
-
$path = str_replace( '\\', '/', $path );
|
32 |
-
$path = preg_replace( '|/+|', '/', $path );
|
33 |
-
|
34 |
-
return $path;
|
35 |
-
}
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
39 |
-
require_once dirname( __FILE__ ) . '/supplements/fs-essential-functions-2.2.1.php';
|
40 |
-
|
41 |
-
#region Core Redirect (copied from BuddyPress) -----------------------------------------
|
42 |
-
|
43 |
-
if ( ! function_exists( 'fs_redirect' ) ) {
|
44 |
-
/**
|
45 |
-
* Redirects to another page, with a workaround for the IIS Set-Cookie bug.
|
46 |
-
*
|
47 |
-
* @link http://support.microsoft.com/kb/q176113/
|
48 |
-
* @since 1.5.1
|
49 |
-
* @uses apply_filters() Calls 'wp_redirect' hook on $location and $status.
|
50 |
-
*
|
51 |
-
* @param string $location The path to redirect to.
|
52 |
-
* @param bool $exit If true, exit after redirect (Since 1.2.1.5).
|
53 |
-
* @param int $status Status code to use.
|
54 |
-
*
|
55 |
-
* @return bool False if $location is not set
|
56 |
-
*/
|
57 |
-
function fs_redirect( $location, $exit = true, $status = 302 ) {
|
58 |
-
global $is_IIS;
|
59 |
-
|
60 |
-
$file = '';
|
61 |
-
$line = '';
|
62 |
-
if ( headers_sent($file, $line) ) {
|
63 |
-
if ( WP_FS__DEBUG_SDK && class_exists( 'FS_Admin_Notices' ) ) {
|
64 |
-
$notices = FS_Admin_Notices::instance( 'global' );
|
65 |
-
|
66 |
-
$notices->add( "Freemius failed to redirect the page because the headers have been already sent from line <b><code>{$line}</code></b> in file <b><code>{$file}</code></b>. If it's unexpected, it usually happens due to invalid space and/or EOL character(s).", 'Oops...', 'error' );
|
67 |
-
}
|
68 |
-
|
69 |
-
return false;
|
70 |
-
}
|
71 |
-
|
72 |
-
if ( defined( 'DOING_AJAX' ) ) {
|
73 |
-
// Don't redirect on AJAX calls.
|
74 |
-
return false;
|
75 |
-
}
|
76 |
-
|
77 |
-
if ( ! $location ) // allows the wp_redirect filter to cancel a redirect
|
78 |
-
{
|
79 |
-
return false;
|
80 |
-
}
|
81 |
-
|
82 |
-
$location = fs_sanitize_redirect( $location );
|
83 |
-
|
84 |
-
if ( $is_IIS ) {
|
85 |
-
header( "Refresh: 0;url=$location" );
|
86 |
-
} else {
|
87 |
-
if ( php_sapi_name() != 'cgi-fcgi' ) {
|
88 |
-
status_header( $status );
|
89 |
-
} // This causes problems on IIS and some FastCGI setups
|
90 |
-
header( "Location: $location" );
|
91 |
-
}
|
92 |
-
|
93 |
-
if ( $exit ) {
|
94 |
-
exit();
|
95 |
-
}
|
96 |
-
|
97 |
-
return true;
|
98 |
-
}
|
99 |
-
|
100 |
-
if ( ! function_exists( 'fs_sanitize_redirect' ) ) {
|
101 |
-
/**
|
102 |
-
* Sanitizes a URL for use in a redirect.
|
103 |
-
*
|
104 |
-
* @since 2.3
|
105 |
-
*
|
106 |
-
* @param string $location
|
107 |
-
*
|
108 |
-
* @return string redirect-sanitized URL
|
109 |
-
*/
|
110 |
-
function fs_sanitize_redirect( $location ) {
|
111 |
-
$location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!]|i', '', $location );
|
112 |
-
$location = fs_kses_no_null( $location );
|
113 |
-
|
114 |
-
// remove %0d and %0a from location
|
115 |
-
$strip = array( '%0d', '%0a' );
|
116 |
-
$found = true;
|
117 |
-
while ( $found ) {
|
118 |
-
$found = false;
|
119 |
-
foreach ( (array) $strip as $val ) {
|
120 |
-
while ( strpos( $location, $val ) !== false ) {
|
121 |
-
$found = true;
|
122 |
-
$location = str_replace( $val, '', $location );
|
123 |
-
}
|
124 |
-
}
|
125 |
-
}
|
126 |
-
|
127 |
-
return $location;
|
128 |
-
}
|
129 |
-
}
|
130 |
-
|
131 |
-
if ( ! function_exists( 'fs_kses_no_null' ) ) {
|
132 |
-
/**
|
133 |
-
* Removes any NULL characters in $string.
|
134 |
-
*
|
135 |
-
* @since 1.0.0
|
136 |
-
*
|
137 |
-
* @param string $string
|
138 |
-
*
|
139 |
-
* @return string
|
140 |
-
*/
|
141 |
-
function fs_kses_no_null( $string ) {
|
142 |
-
$string = preg_replace( '/\0+/', '', $string );
|
143 |
-
$string = preg_replace( '/(\\\\0)+/', '', $string );
|
144 |
-
|
145 |
-
return $string;
|
146 |
-
}
|
147 |
-
}
|
148 |
-
}
|
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 |
-
|
260 |
-
/**
|
261 |
-
* Leverage backtrace to find caller plugin main file path.
|
262 |
-
*
|
263 |
-
* @author Vova Feldman (@svovaf)
|
264 |
-
* @since 1.0.6
|
265 |
-
*
|
266 |
-
* @return string
|
267 |
-
*/
|
268 |
-
function fs_find_caller_plugin_file() {
|
269 |
-
/**
|
270 |
-
* All the code below will be executed once on activation.
|
271 |
-
* If the user changes the main plugin's file name, the file_exists()
|
272 |
-
* will catch it.
|
273 |
-
*/
|
274 |
-
if ( ! function_exists( 'get_plugins' ) ) {
|
275 |
-
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
276 |
-
}
|
277 |
-
|
278 |
-
$all_plugins = fs_get_plugins( true );
|
279 |
-
$all_plugins_paths = array();
|
280 |
-
|
281 |
-
// Get active plugin's main files real full names (might be symlinks).
|
282 |
-
foreach ( $all_plugins as $relative_path => $data ) {
|
283 |
-
$all_plugins_paths[] = fs_normalize_path( realpath( WP_PLUGIN_DIR . '/' . $relative_path ) );
|
284 |
-
}
|
285 |
-
|
286 |
-
$plugin_file = null;
|
287 |
-
for ( $i = 1, $bt = debug_backtrace(), $len = count( $bt ); $i < $len; $i ++ ) {
|
288 |
-
if ( empty( $bt[ $i ]['file'] ) ) {
|
289 |
-
continue;
|
290 |
-
}
|
291 |
-
|
292 |
-
if ( in_array( fs_normalize_path( $bt[ $i ]['file'] ), $all_plugins_paths ) ) {
|
293 |
-
$plugin_file = $bt[ $i ]['file'];
|
294 |
-
break;
|
295 |
-
}
|
296 |
-
}
|
297 |
-
|
298 |
-
if ( is_null( $plugin_file ) ) {
|
299 |
-
// Throw an error to the developer in case of some edge case dev environment.
|
300 |
-
wp_die(
|
301 |
-
'Freemius SDK couldn\'t find the plugin\'s main file. Please contact sdk@freemius.com with the current error.',
|
302 |
-
'Error',
|
303 |
-
array( 'back_link' => true )
|
304 |
-
);
|
305 |
-
}
|
306 |
-
|
307 |
-
return $plugin_file;
|
308 |
-
}
|
309 |
-
|
310 |
-
require_once dirname( __FILE__ ) . '/supplements/fs-essential-functions-1.1.7.1.php';
|
311 |
-
|
312 |
-
/**
|
313 |
-
* Update SDK newest version reference.
|
314 |
-
*
|
315 |
-
* @author Vova Feldman (@svovaf)
|
316 |
-
* @since 1.1.6
|
317 |
-
*
|
318 |
-
* @param string $sdk_relative_path
|
319 |
-
* @param string|bool $plugin_file
|
320 |
-
*
|
321 |
-
* @global $fs_active_plugins
|
322 |
-
*/
|
323 |
-
function fs_update_sdk_newest_version( $sdk_relative_path, $plugin_file = false ) {
|
324 |
-
/**
|
325 |
-
* If there is a plugin running an older version of FS (1.2.1 or below), the `fs_update_sdk_newest_version()`
|
326 |
-
* function in the older version will be used instead of this one. But since the older version is using
|
327 |
-
* the `is_plugin_active` function to check if a plugin is active, passing the theme's `plugin_path` to the
|
328 |
-
* `is_plugin_active` function will return false since the path is not a plugin path, so `in_activation` will be
|
329 |
-
* `true` for theme modules and the upgrading of the SDK version to 1.2.2 or newer version will work fine.
|
330 |
-
*
|
331 |
-
* Future versions that will call this function will use the proper logic here instead of just relying on the
|
332 |
-
* `is_plugin_active` function to fail for themes.
|
333 |
-
*
|
334 |
-
* @author Leo Fajardo (@leorw)
|
335 |
-
* @since 1.2.2
|
336 |
-
*/
|
337 |
-
|
338 |
-
global $fs_active_plugins;
|
339 |
-
|
340 |
-
$newest_sdk = $fs_active_plugins->plugins[ $sdk_relative_path ];
|
341 |
-
|
342 |
-
if ( ! is_string( $plugin_file ) ) {
|
343 |
-
$plugin_file = plugin_basename( fs_find_caller_plugin_file() );
|
344 |
-
}
|
345 |
-
|
346 |
-
if ( ! isset( $newest_sdk->type ) || 'theme' !== $newest_sdk->type ) {
|
347 |
-
if ( ! function_exists( 'is_plugin_active' ) ) {
|
348 |
-
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
349 |
-
}
|
350 |
-
|
351 |
-
$in_activation = ( ! is_plugin_active( $plugin_file ) );
|
352 |
-
} else {
|
353 |
-
$theme = wp_get_theme();
|
354 |
-
$in_activation = ( $newest_sdk->plugin_path == $theme->stylesheet );
|
355 |
-
}
|
356 |
-
|
357 |
-
$fs_active_plugins->newest = (object) array(
|
358 |
-
'plugin_path' => $plugin_file,
|
359 |
-
'sdk_path' => $sdk_relative_path,
|
360 |
-
'version' => $newest_sdk->version,
|
361 |
-
'in_activation' => $in_activation,
|
362 |
-
'timestamp' => time(),
|
363 |
-
);
|
364 |
-
|
365 |
-
// Update DB with latest SDK version and path.
|
366 |
-
update_option( 'fs_active_plugins', $fs_active_plugins );
|
367 |
-
}
|
368 |
-
|
369 |
-
/**
|
370 |
-
* Reorder the plugins load order so the plugin with the newest Freemius SDK is loaded first.
|
371 |
-
*
|
372 |
-
* @author Vova Feldman (@svovaf)
|
373 |
-
* @since 1.1.6
|
374 |
-
*
|
375 |
-
* @return bool Was plugin order changed. Return false if plugin was loaded first anyways.
|
376 |
-
*
|
377 |
-
* @global $fs_active_plugins
|
378 |
-
*/
|
379 |
-
function fs_newest_sdk_plugin_first() {
|
380 |
-
global $fs_active_plugins;
|
381 |
-
|
382 |
-
/**
|
383 |
-
* @todo Multi-site network activated plugin are always loaded prior to site plugins so if there's a plugin activated in the network mode that has an older version of the SDK of another plugin which is site activated that has new SDK version, the fs-essential-functions.php will be loaded from the older SDK. Same thing about MU plugins (loaded even before network activated plugins).
|
384 |
-
*
|
385 |
-
* @link https://github.com/Freemius/wordpress-sdk/issues/26
|
386 |
-
*/
|
387 |
-
|
388 |
-
$newest_sdk_plugin_path = $fs_active_plugins->newest->plugin_path;
|
389 |
-
|
390 |
-
$active_plugins = get_option( 'active_plugins', array() );
|
391 |
-
$updated_active_plugins = array( $newest_sdk_plugin_path );
|
392 |
-
|
393 |
-
$plugin_found = false;
|
394 |
-
$is_first_path = true;
|
395 |
-
|
396 |
-
foreach ( $active_plugins as $key => $plugin_path ) {
|
397 |
-
if ( $plugin_path === $newest_sdk_plugin_path ) {
|
398 |
-
if ( $is_first_path ) {
|
399 |
-
// if it's the first plugin already, no need to continue
|
400 |
-
return false;
|
401 |
-
}
|
402 |
-
|
403 |
-
$plugin_found = true;
|
404 |
-
|
405 |
-
// Skip the plugin (it is already added as the 1st item of $updated_active_plugins).
|
406 |
-
continue;
|
407 |
-
}
|
408 |
-
|
409 |
-
$updated_active_plugins[] = $plugin_path;
|
410 |
-
|
411 |
-
if ( $is_first_path ) {
|
412 |
-
$is_first_path = false;
|
413 |
-
}
|
414 |
-
}
|
415 |
-
|
416 |
-
if ( $plugin_found ) {
|
417 |
-
update_option( 'active_plugins', $updated_active_plugins );
|
418 |
-
|
419 |
-
return true;
|
420 |
-
}
|
421 |
-
|
422 |
-
if ( is_multisite() ) {
|
423 |
-
// Plugin is network active.
|
424 |
-
$network_active_plugins = get_site_option( 'active_sitewide_plugins', array() );
|
425 |
-
|
426 |
-
if ( isset( $network_active_plugins[ $newest_sdk_plugin_path ] ) ) {
|
427 |
-
reset( $network_active_plugins );
|
428 |
-
if ( $newest_sdk_plugin_path === key( $network_active_plugins ) ) {
|
429 |
-
// Plugin is already activated first on the network level.
|
430 |
-
return false;
|
431 |
-
} else {
|
432 |
-
$time = $network_active_plugins[ $newest_sdk_plugin_path ];
|
433 |
-
|
434 |
-
// Remove plugin from its current position.
|
435 |
-
unset( $network_active_plugins[ $newest_sdk_plugin_path ] );
|
436 |
-
|
437 |
-
// Set it to be included first.
|
438 |
-
$network_active_plugins = array( $newest_sdk_plugin_path => $time ) + $network_active_plugins;
|
439 |
-
|
440 |
-
update_site_option( 'active_sitewide_plugins', $network_active_plugins );
|
441 |
-
|
442 |
-
return true;
|
443 |
-
}
|
444 |
-
}
|
445 |
-
}
|
446 |
-
|
447 |
-
return false;
|
448 |
-
}
|
449 |
-
|
450 |
-
/**
|
451 |
-
* Go over all Freemius SDKs in the system and find and "remember"
|
452 |
-
* the newest SDK which is associated with an active plugin.
|
453 |
-
*
|
454 |
-
* @author Vova Feldman (@svovaf)
|
455 |
-
* @since 1.1.6
|
456 |
-
*
|
457 |
-
* @global $fs_active_plugins
|
458 |
-
*/
|
459 |
-
function fs_fallback_to_newest_active_sdk() {
|
460 |
-
global $fs_active_plugins;
|
461 |
-
|
462 |
-
/**
|
463 |
-
* @var object $newest_sdk_data
|
464 |
-
*/
|
465 |
-
$newest_sdk_data = null;
|
466 |
-
$newest_sdk_path = null;
|
467 |
-
|
468 |
-
foreach ( $fs_active_plugins->plugins as $sdk_relative_path => $data ) {
|
469 |
-
if ( is_null( $newest_sdk_data ) || version_compare( $data->version, $newest_sdk_data->version, '>' )
|
470 |
-
) {
|
471 |
-
// If plugin inactive or SDK starter file doesn't exist, remove SDK reference.
|
472 |
-
if ( 'plugin' === $data->type ) {
|
473 |
-
$is_module_active = is_plugin_active( $data->plugin_path );
|
474 |
-
} else {
|
475 |
-
$active_theme = wp_get_theme();
|
476 |
-
$is_module_active = ( $data->plugin_path === $active_theme->get_template() );
|
477 |
-
}
|
478 |
-
|
479 |
-
$is_sdk_exists = file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $sdk_relative_path . '/start.php' ) );
|
480 |
-
|
481 |
-
if ( ! $is_module_active || ! $is_sdk_exists ) {
|
482 |
-
unset( $fs_active_plugins->plugins[ $sdk_relative_path ] );
|
483 |
-
|
484 |
-
// No need to store the data since it will be stored in fs_update_sdk_newest_version()
|
485 |
-
// or explicitly with update_option().
|
486 |
-
} else {
|
487 |
-
$newest_sdk_data = $data;
|
488 |
-
$newest_sdk_path = $sdk_relative_path;
|
489 |
-
}
|
490 |
-
}
|
491 |
-
}
|
492 |
-
|
493 |
-
if ( is_null( $newest_sdk_data ) ) {
|
494 |
-
// Couldn't find any SDK reference.
|
495 |
-
$fs_active_plugins = new stdClass();
|
496 |
-
update_option( 'fs_active_plugins', $fs_active_plugins );
|
497 |
-
} else {
|
498 |
-
fs_update_sdk_newest_version( $newest_sdk_path, $newest_sdk_data->plugin_path );
|
499 |
-
}
|
500 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* IMPORTANT:
|
4 |
+
* This file will be loaded based on the order of the plugins/themes load.
|
5 |
+
* If there's a theme and a plugin using Freemius, the plugin's essential
|
6 |
+
* file will always load first.
|
7 |
+
*
|
8 |
+
* @package Freemius
|
9 |
+
* @copyright Copyright (c) 2015, Freemius, Inc.
|
10 |
+
* @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
|
11 |
+
* @since 1.1.5
|
12 |
+
*/
|
13 |
+
|
14 |
+
if ( ! function_exists( 'fs_normalize_path' ) ) {
|
15 |
+
if ( function_exists( 'wp_normalize_path' ) ) {
|
16 |
+
/**
|
17 |
+
* Normalize a filesystem path.
|
18 |
+
*
|
19 |
+
* Replaces backslashes with forward slashes for Windows systems, and ensures
|
20 |
+
* no duplicate slashes exist.
|
21 |
+
*
|
22 |
+
* @param string $path Path to normalize.
|
23 |
+
*
|
24 |
+
* @return string Normalized path.
|
25 |
+
*/
|
26 |
+
function fs_normalize_path( $path ) {
|
27 |
+
return wp_normalize_path( $path );
|
28 |
+
}
|
29 |
+
} else {
|
30 |
+
function fs_normalize_path( $path ) {
|
31 |
+
$path = str_replace( '\\', '/', $path );
|
32 |
+
$path = preg_replace( '|/+|', '/', $path );
|
33 |
+
|
34 |
+
return $path;
|
35 |
+
}
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
require_once dirname( __FILE__ ) . '/supplements/fs-essential-functions-2.2.1.php';
|
40 |
+
|
41 |
+
#region Core Redirect (copied from BuddyPress) -----------------------------------------
|
42 |
+
|
43 |
+
if ( ! function_exists( 'fs_redirect' ) ) {
|
44 |
+
/**
|
45 |
+
* Redirects to another page, with a workaround for the IIS Set-Cookie bug.
|
46 |
+
*
|
47 |
+
* @link http://support.microsoft.com/kb/q176113/
|
48 |
+
* @since 1.5.1
|
49 |
+
* @uses apply_filters() Calls 'wp_redirect' hook on $location and $status.
|
50 |
+
*
|
51 |
+
* @param string $location The path to redirect to.
|
52 |
+
* @param bool $exit If true, exit after redirect (Since 1.2.1.5).
|
53 |
+
* @param int $status Status code to use.
|
54 |
+
*
|
55 |
+
* @return bool False if $location is not set
|
56 |
+
*/
|
57 |
+
function fs_redirect( $location, $exit = true, $status = 302 ) {
|
58 |
+
global $is_IIS;
|
59 |
+
|
60 |
+
$file = '';
|
61 |
+
$line = '';
|
62 |
+
if ( headers_sent($file, $line) ) {
|
63 |
+
if ( WP_FS__DEBUG_SDK && class_exists( 'FS_Admin_Notices' ) ) {
|
64 |
+
$notices = FS_Admin_Notices::instance( 'global' );
|
65 |
+
|
66 |
+
$notices->add( "Freemius failed to redirect the page because the headers have been already sent from line <b><code>{$line}</code></b> in file <b><code>{$file}</code></b>. If it's unexpected, it usually happens due to invalid space and/or EOL character(s).", 'Oops...', 'error' );
|
67 |
+
}
|
68 |
+
|
69 |
+
return false;
|
70 |
+
}
|
71 |
+
|
72 |
+
if ( defined( 'DOING_AJAX' ) ) {
|
73 |
+
// Don't redirect on AJAX calls.
|
74 |
+
return false;
|
75 |
+
}
|
76 |
+
|
77 |
+
if ( ! $location ) // allows the wp_redirect filter to cancel a redirect
|
78 |
+
{
|
79 |
+
return false;
|
80 |
+
}
|
81 |
+
|
82 |
+
$location = fs_sanitize_redirect( $location );
|
83 |
+
|
84 |
+
if ( $is_IIS ) {
|
85 |
+
header( "Refresh: 0;url=$location" );
|
86 |
+
} else {
|
87 |
+
if ( php_sapi_name() != 'cgi-fcgi' ) {
|
88 |
+
status_header( $status );
|
89 |
+
} // This causes problems on IIS and some FastCGI setups
|
90 |
+
header( "Location: $location" );
|
91 |
+
}
|
92 |
+
|
93 |
+
if ( $exit ) {
|
94 |
+
exit();
|
95 |
+
}
|
96 |
+
|
97 |
+
return true;
|
98 |
+
}
|
99 |
+
|
100 |
+
if ( ! function_exists( 'fs_sanitize_redirect' ) ) {
|
101 |
+
/**
|
102 |
+
* Sanitizes a URL for use in a redirect.
|
103 |
+
*
|
104 |
+
* @since 2.3
|
105 |
+
*
|
106 |
+
* @param string $location
|
107 |
+
*
|
108 |
+
* @return string redirect-sanitized URL
|
109 |
+
*/
|
110 |
+
function fs_sanitize_redirect( $location ) {
|
111 |
+
$location = preg_replace( '|[^a-z0-9-~+_.?#=&;,/:%!]|i', '', $location );
|
112 |
+
$location = fs_kses_no_null( $location );
|
113 |
+
|
114 |
+
// remove %0d and %0a from location
|
115 |
+
$strip = array( '%0d', '%0a' );
|
116 |
+
$found = true;
|
117 |
+
while ( $found ) {
|
118 |
+
$found = false;
|
119 |
+
foreach ( (array) $strip as $val ) {
|
120 |
+
while ( strpos( $location, $val ) !== false ) {
|
121 |
+
$found = true;
|
122 |
+
$location = str_replace( $val, '', $location );
|
123 |
+
}
|
124 |
+
}
|
125 |
+
}
|
126 |
+
|
127 |
+
return $location;
|
128 |
+
}
|
129 |
+
}
|
130 |
+
|
131 |
+
if ( ! function_exists( 'fs_kses_no_null' ) ) {
|
132 |
+
/**
|
133 |
+
* Removes any NULL characters in $string.
|
134 |
+
*
|
135 |
+
* @since 1.0.0
|
136 |
+
*
|
137 |
+
* @param string $string
|
138 |
+
*
|
139 |
+
* @return string
|
140 |
+
*/
|
141 |
+
function fs_kses_no_null( $string ) {
|
142 |
+
$string = preg_replace( '/\0+/', '', $string );
|
143 |
+
$string = preg_replace( '/(\\\\0)+/', '', $string );
|
144 |
+
|
145 |
+
return $string;
|
146 |
+
}
|
147 |
+
}
|
148 |
+
}
|
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 |
+
|
260 |
+
/**
|
261 |
+
* Leverage backtrace to find caller plugin main file path.
|
262 |
+
*
|
263 |
+
* @author Vova Feldman (@svovaf)
|
264 |
+
* @since 1.0.6
|
265 |
+
*
|
266 |
+
* @return string
|
267 |
+
*/
|
268 |
+
function fs_find_caller_plugin_file() {
|
269 |
+
/**
|
270 |
+
* All the code below will be executed once on activation.
|
271 |
+
* If the user changes the main plugin's file name, the file_exists()
|
272 |
+
* will catch it.
|
273 |
+
*/
|
274 |
+
if ( ! function_exists( 'get_plugins' ) ) {
|
275 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
276 |
+
}
|
277 |
+
|
278 |
+
$all_plugins = fs_get_plugins( true );
|
279 |
+
$all_plugins_paths = array();
|
280 |
+
|
281 |
+
// Get active plugin's main files real full names (might be symlinks).
|
282 |
+
foreach ( $all_plugins as $relative_path => $data ) {
|
283 |
+
$all_plugins_paths[] = fs_normalize_path( realpath( WP_PLUGIN_DIR . '/' . $relative_path ) );
|
284 |
+
}
|
285 |
+
|
286 |
+
$plugin_file = null;
|
287 |
+
for ( $i = 1, $bt = debug_backtrace(), $len = count( $bt ); $i < $len; $i ++ ) {
|
288 |
+
if ( empty( $bt[ $i ]['file'] ) ) {
|
289 |
+
continue;
|
290 |
+
}
|
291 |
+
|
292 |
+
if ( in_array( fs_normalize_path( $bt[ $i ]['file'] ), $all_plugins_paths ) ) {
|
293 |
+
$plugin_file = $bt[ $i ]['file'];
|
294 |
+
break;
|
295 |
+
}
|
296 |
+
}
|
297 |
+
|
298 |
+
if ( is_null( $plugin_file ) ) {
|
299 |
+
// Throw an error to the developer in case of some edge case dev environment.
|
300 |
+
wp_die(
|
301 |
+
'Freemius SDK couldn\'t find the plugin\'s main file. Please contact sdk@freemius.com with the current error.',
|
302 |
+
'Error',
|
303 |
+
array( 'back_link' => true )
|
304 |
+
);
|
305 |
+
}
|
306 |
+
|
307 |
+
return $plugin_file;
|
308 |
+
}
|
309 |
+
|
310 |
+
require_once dirname( __FILE__ ) . '/supplements/fs-essential-functions-1.1.7.1.php';
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Update SDK newest version reference.
|
314 |
+
*
|
315 |
+
* @author Vova Feldman (@svovaf)
|
316 |
+
* @since 1.1.6
|
317 |
+
*
|
318 |
+
* @param string $sdk_relative_path
|
319 |
+
* @param string|bool $plugin_file
|
320 |
+
*
|
321 |
+
* @global $fs_active_plugins
|
322 |
+
*/
|
323 |
+
function fs_update_sdk_newest_version( $sdk_relative_path, $plugin_file = false ) {
|
324 |
+
/**
|
325 |
+
* If there is a plugin running an older version of FS (1.2.1 or below), the `fs_update_sdk_newest_version()`
|
326 |
+
* function in the older version will be used instead of this one. But since the older version is using
|
327 |
+
* the `is_plugin_active` function to check if a plugin is active, passing the theme's `plugin_path` to the
|
328 |
+
* `is_plugin_active` function will return false since the path is not a plugin path, so `in_activation` will be
|
329 |
+
* `true` for theme modules and the upgrading of the SDK version to 1.2.2 or newer version will work fine.
|
330 |
+
*
|
331 |
+
* Future versions that will call this function will use the proper logic here instead of just relying on the
|
332 |
+
* `is_plugin_active` function to fail for themes.
|
333 |
+
*
|
334 |
+
* @author Leo Fajardo (@leorw)
|
335 |
+
* @since 1.2.2
|
336 |
+
*/
|
337 |
+
|
338 |
+
global $fs_active_plugins;
|
339 |
+
|
340 |
+
$newest_sdk = $fs_active_plugins->plugins[ $sdk_relative_path ];
|
341 |
+
|
342 |
+
if ( ! is_string( $plugin_file ) ) {
|
343 |
+
$plugin_file = plugin_basename( fs_find_caller_plugin_file() );
|
344 |
+
}
|
345 |
+
|
346 |
+
if ( ! isset( $newest_sdk->type ) || 'theme' !== $newest_sdk->type ) {
|
347 |
+
if ( ! function_exists( 'is_plugin_active' ) ) {
|
348 |
+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
349 |
+
}
|
350 |
+
|
351 |
+
$in_activation = ( ! is_plugin_active( $plugin_file ) );
|
352 |
+
} else {
|
353 |
+
$theme = wp_get_theme();
|
354 |
+
$in_activation = ( $newest_sdk->plugin_path == $theme->stylesheet );
|
355 |
+
}
|
356 |
+
|
357 |
+
$fs_active_plugins->newest = (object) array(
|
358 |
+
'plugin_path' => $plugin_file,
|
359 |
+
'sdk_path' => $sdk_relative_path,
|
360 |
+
'version' => $newest_sdk->version,
|
361 |
+
'in_activation' => $in_activation,
|
362 |
+
'timestamp' => time(),
|
363 |
+
);
|
364 |
+
|
365 |
+
// Update DB with latest SDK version and path.
|
366 |
+
update_option( 'fs_active_plugins', $fs_active_plugins );
|
367 |
+
}
|
368 |
+
|
369 |
+
/**
|
370 |
+
* Reorder the plugins load order so the plugin with the newest Freemius SDK is loaded first.
|
371 |
+
*
|
372 |
+
* @author Vova Feldman (@svovaf)
|
373 |
+
* @since 1.1.6
|
374 |
+
*
|
375 |
+
* @return bool Was plugin order changed. Return false if plugin was loaded first anyways.
|
376 |
+
*
|
377 |
+
* @global $fs_active_plugins
|
378 |
+
*/
|
379 |
+
function fs_newest_sdk_plugin_first() {
|
380 |
+
global $fs_active_plugins;
|
381 |
+
|
382 |
+
/**
|
383 |
+
* @todo Multi-site network activated plugin are always loaded prior to site plugins so if there's a plugin activated in the network mode that has an older version of the SDK of another plugin which is site activated that has new SDK version, the fs-essential-functions.php will be loaded from the older SDK. Same thing about MU plugins (loaded even before network activated plugins).
|
384 |
+
*
|
385 |
+
* @link https://github.com/Freemius/wordpress-sdk/issues/26
|
386 |
+
*/
|
387 |
+
|
388 |
+
$newest_sdk_plugin_path = $fs_active_plugins->newest->plugin_path;
|
389 |
+
|
390 |
+
$active_plugins = get_option( 'active_plugins', array() );
|
391 |
+
$updated_active_plugins = array( $newest_sdk_plugin_path );
|
392 |
+
|
393 |
+
$plugin_found = false;
|
394 |
+
$is_first_path = true;
|
395 |
+
|
396 |
+
foreach ( $active_plugins as $key => $plugin_path ) {
|
397 |
+
if ( $plugin_path === $newest_sdk_plugin_path ) {
|
398 |
+
if ( $is_first_path ) {
|
399 |
+
// if it's the first plugin already, no need to continue
|
400 |
+
return false;
|
401 |
+
}
|
402 |
+
|
403 |
+
$plugin_found = true;
|
404 |
+
|
405 |
+
// Skip the plugin (it is already added as the 1st item of $updated_active_plugins).
|
406 |
+
continue;
|
407 |
+
}
|
408 |
+
|
409 |
+
$updated_active_plugins[] = $plugin_path;
|
410 |
+
|
411 |
+
if ( $is_first_path ) {
|
412 |
+
$is_first_path = false;
|
413 |
+
}
|
414 |
+
}
|
415 |
+
|
416 |
+
if ( $plugin_found ) {
|
417 |
+
update_option( 'active_plugins', $updated_active_plugins );
|
418 |
+
|
419 |
+
return true;
|
420 |
+
}
|
421 |
+
|
422 |
+
if ( is_multisite() ) {
|
423 |
+
// Plugin is network active.
|
424 |
+
$network_active_plugins = get_site_option( 'active_sitewide_plugins', array() );
|
425 |
+
|
426 |
+
if ( isset( $network_active_plugins[ $newest_sdk_plugin_path ] ) ) {
|
427 |
+
reset( $network_active_plugins );
|
428 |
+
if ( $newest_sdk_plugin_path === key( $network_active_plugins ) ) {
|
429 |
+
// Plugin is already activated first on the network level.
|
430 |
+
return false;
|
431 |
+
} else {
|
432 |
+
$time = $network_active_plugins[ $newest_sdk_plugin_path ];
|
433 |
+
|
434 |
+
// Remove plugin from its current position.
|
435 |
+
unset( $network_active_plugins[ $newest_sdk_plugin_path ] );
|
436 |
+
|
437 |
+
// Set it to be included first.
|
438 |
+
$network_active_plugins = array( $newest_sdk_plugin_path => $time ) + $network_active_plugins;
|
439 |
+
|
440 |
+
update_site_option( 'active_sitewide_plugins', $network_active_plugins );
|
441 |
+
|
442 |
+
return true;
|
443 |
+
}
|
444 |
+
}
|
445 |
+
}
|
446 |
+
|
447 |
+
return false;
|
448 |
+
}
|
449 |
+
|
450 |
+
/**
|
451 |
+
* Go over all Freemius SDKs in the system and find and "remember"
|
452 |
+
* the newest SDK which is associated with an active plugin.
|
453 |
+
*
|
454 |
+
* @author Vova Feldman (@svovaf)
|
455 |
+
* @since 1.1.6
|
456 |
+
*
|
457 |
+
* @global $fs_active_plugins
|
458 |
+
*/
|
459 |
+
function fs_fallback_to_newest_active_sdk() {
|
460 |
+
global $fs_active_plugins;
|
461 |
+
|
462 |
+
/**
|
463 |
+
* @var object $newest_sdk_data
|
464 |
+
*/
|
465 |
+
$newest_sdk_data = null;
|
466 |
+
$newest_sdk_path = null;
|
467 |
+
|
468 |
+
foreach ( $fs_active_plugins->plugins as $sdk_relative_path => $data ) {
|
469 |
+
if ( is_null( $newest_sdk_data ) || version_compare( $data->version, $newest_sdk_data->version, '>' )
|
470 |
+
) {
|
471 |
+
// If plugin inactive or SDK starter file doesn't exist, remove SDK reference.
|
472 |
+
if ( 'plugin' === $data->type ) {
|
473 |
+
$is_module_active = is_plugin_active( $data->plugin_path );
|
474 |
+
} else {
|
475 |
+
$active_theme = wp_get_theme();
|
476 |
+
$is_module_active = ( $data->plugin_path === $active_theme->get_template() );
|
477 |
+
}
|
478 |
+
|
479 |
+
$is_sdk_exists = file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $sdk_relative_path . '/start.php' ) );
|
480 |
+
|
481 |
+
if ( ! $is_module_active || ! $is_sdk_exists ) {
|
482 |
+
unset( $fs_active_plugins->plugins[ $sdk_relative_path ] );
|
483 |
+
|
484 |
+
// No need to store the data since it will be stored in fs_update_sdk_newest_version()
|
485 |
+
// or explicitly with update_option().
|
486 |
+
} else {
|
487 |
+
$newest_sdk_data = $data;
|
488 |
+
$newest_sdk_path = $sdk_relative_path;
|
489 |
+
}
|
490 |
+
}
|
491 |
+
}
|
492 |
+
|
493 |
+
if ( is_null( $newest_sdk_data ) ) {
|
494 |
+
// Couldn't find any SDK reference.
|
495 |
+
$fs_active_plugins = new stdClass();
|
496 |
+
update_option( 'fs_active_plugins', $fs_active_plugins );
|
497 |
+
} else {
|
498 |
+
fs_update_sdk_newest_version( $newest_sdk_path, $newest_sdk_data->plugin_path );
|
499 |
+
}
|
500 |
}
|
freemius/includes/fs-plugin-info-dialog.php
CHANGED
@@ -1,1644 +1,1644 @@
|
|
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 1.0.6
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Class FS_Plugin_Info_Dialog
|
15 |
-
*
|
16 |
-
* @author Vova Feldman (@svovaf)
|
17 |
-
* @since 1.1.7
|
18 |
-
*/
|
19 |
-
class FS_Plugin_Info_Dialog {
|
20 |
-
/**
|
21 |
-
* @since 1.1.7
|
22 |
-
*
|
23 |
-
* @var FS_Logger
|
24 |
-
*/
|
25 |
-
private $_logger;
|
26 |
-
|
27 |
-
/**
|
28 |
-
* @since 1.1.7
|
29 |
-
*
|
30 |
-
* @var Freemius
|
31 |
-
*/
|
32 |
-
private $_fs;
|
33 |
-
|
34 |
-
/**
|
35 |
-
* Collection of plugin installation, update, download, activation, and purchase actions. This is used in
|
36 |
-
* populating the actions dropdown list when there are at least 2 actions. If there's only 1 action, a button
|
37 |
-
* is used instead.
|
38 |
-
*
|
39 |
-
* @author Leo Fajardo (@leorw)
|
40 |
-
* @since 2.3.0
|
41 |
-
*
|
42 |
-
* @var string[]
|
43 |
-
*/
|
44 |
-
private $actions;
|
45 |
-
|
46 |
-
/**
|
47 |
-
* Contains plugin status information that is used to determine which actions should be part of the actions
|
48 |
-
* dropdown list.
|
49 |
-
*
|
50 |
-
* @author Leo Fajardo (@leorw)
|
51 |
-
* @since 2.3.0
|
52 |
-
*
|
53 |
-
* @var string[]
|
54 |
-
*/
|
55 |
-
private $status;
|
56 |
-
|
57 |
-
function __construct( Freemius $fs ) {
|
58 |
-
$this->_fs = $fs;
|
59 |
-
|
60 |
-
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $fs->get_slug() . '_info', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
61 |
-
|
62 |
-
// Remove default plugin information action.
|
63 |
-
remove_all_actions( 'install_plugins_pre_plugin-information' );
|
64 |
-
|
65 |
-
// Override action with custom plugins function for add-ons.
|
66 |
-
add_action( 'install_plugins_pre_plugin-information', array( &$this, 'install_plugin_information' ) );
|
67 |
-
|
68 |
-
// Override request for plugin information for Add-ons.
|
69 |
-
add_filter(
|
70 |
-
'fs_plugins_api',
|
71 |
-
array( &$this, '_get_addon_info_filter' ),
|
72 |
-
WP_FS__DEFAULT_PRIORITY, 3 );
|
73 |
-
}
|
74 |
-
|
75 |
-
/**
|
76 |
-
* Generate add-on plugin information.
|
77 |
-
*
|
78 |
-
* @author Vova Feldman (@svovaf)
|
79 |
-
* @since 1.0.6
|
80 |
-
*
|
81 |
-
* @param array $data
|
82 |
-
* @param string $action
|
83 |
-
* @param object|null $args
|
84 |
-
*
|
85 |
-
* @return array|null
|
86 |
-
*/
|
87 |
-
function _get_addon_info_filter( $data, $action = '', $args = null ) {
|
88 |
-
$this->_logger->entrance();
|
89 |
-
|
90 |
-
$parent_plugin_id = fs_request_get( 'parent_plugin_id', $this->_fs->get_id() );
|
91 |
-
|
92 |
-
if ( $this->_fs->get_id() != $parent_plugin_id ||
|
93 |
-
( 'plugin_information' !== $action ) ||
|
94 |
-
! isset( $args->slug )
|
95 |
-
) {
|
96 |
-
return $data;
|
97 |
-
}
|
98 |
-
|
99 |
-
// Find add-on by slug.
|
100 |
-
$selected_addon = $this->_fs->get_addon_by_slug( $args->slug, WP_FS__DEV_MODE );
|
101 |
-
|
102 |
-
if ( false === $selected_addon ) {
|
103 |
-
return $data;
|
104 |
-
}
|
105 |
-
|
106 |
-
if ( ! isset( $selected_addon->info ) ) {
|
107 |
-
// Setup some default info.
|
108 |
-
$selected_addon->info = new stdClass();
|
109 |
-
$selected_addon->info->selling_point_0 = 'Selling Point 1';
|
110 |
-
$selected_addon->info->selling_point_1 = 'Selling Point 2';
|
111 |
-
$selected_addon->info->selling_point_2 = 'Selling Point 3';
|
112 |
-
$selected_addon->info->description = '<p>Tell your users all about your add-on</p>';
|
113 |
-
}
|
114 |
-
|
115 |
-
fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
|
116 |
-
|
117 |
-
$data = $args;
|
118 |
-
|
119 |
-
$has_free_plan = false;
|
120 |
-
$has_paid_plan = false;
|
121 |
-
|
122 |
-
// Load add-on pricing.
|
123 |
-
$has_pricing = false;
|
124 |
-
$has_features = false;
|
125 |
-
$plans = false;
|
126 |
-
|
127 |
-
$result = $this->_fs->get_api_plugin_scope()->get( $this->_fs->add_show_pending( "/addons/{$selected_addon->id}/pricing.json?type=visible" ) );
|
128 |
-
|
129 |
-
if ( ! isset( $result->error ) ) {
|
130 |
-
$plans = $result->plans;
|
131 |
-
|
132 |
-
if ( is_array( $plans ) ) {
|
133 |
-
for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
|
134 |
-
$pricing = isset( $plans[ $i ]->pricing ) ? $plans[ $i ]->pricing : null;
|
135 |
-
$features = isset( $plans[ $i ]->features ) ? $plans[ $i ]->features : null;
|
136 |
-
|
137 |
-
$plans[ $i ] = new FS_Plugin_Plan( $plans[ $i ] );
|
138 |
-
$plan = $plans[ $i ];
|
139 |
-
|
140 |
-
if ( 'free' == $plans[ $i ]->name ||
|
141 |
-
! is_array( $pricing ) ||
|
142 |
-
0 == count( $pricing )
|
143 |
-
) {
|
144 |
-
$has_free_plan = true;
|
145 |
-
}
|
146 |
-
|
147 |
-
if ( is_array( $pricing ) && 0 < count( $pricing ) ) {
|
148 |
-
$filtered_pricing = array();
|
149 |
-
|
150 |
-
foreach ( $pricing as $prices ) {
|
151 |
-
$prices = new FS_Pricing( $prices );
|
152 |
-
|
153 |
-
if ( ! $prices->is_usd() ) {
|
154 |
-
/**
|
155 |
-
* Skip non-USD pricing.
|
156 |
-
*
|
157 |
-
* @author Leo Fajardo (@leorw)
|
158 |
-
* @since 2.3.1
|
159 |
-
*/
|
160 |
-
continue;
|
161 |
-
}
|
162 |
-
|
163 |
-
if ( ( $prices->has_monthly() && $prices->monthly_price > 1.0 ) ||
|
164 |
-
( $prices->has_annual() && $prices->annual_price > 1.0 ) ||
|
165 |
-
( $prices->has_lifetime() && $prices->lifetime_price > 1.0 )
|
166 |
-
) {
|
167 |
-
$filtered_pricing[] = $prices;
|
168 |
-
}
|
169 |
-
}
|
170 |
-
|
171 |
-
if ( ! empty( $filtered_pricing ) ) {
|
172 |
-
$has_paid_plan = true;
|
173 |
-
|
174 |
-
$plan->pricing = $filtered_pricing;
|
175 |
-
|
176 |
-
$has_pricing = true;
|
177 |
-
}
|
178 |
-
}
|
179 |
-
|
180 |
-
if ( is_array( $features ) && 0 < count( $features ) ) {
|
181 |
-
$plan->features = $features;
|
182 |
-
|
183 |
-
$has_features = true;
|
184 |
-
}
|
185 |
-
}
|
186 |
-
}
|
187 |
-
}
|
188 |
-
|
189 |
-
$latest = null;
|
190 |
-
|
191 |
-
if ( ! $has_paid_plan && $selected_addon->is_wp_org_compliant ) {
|
192 |
-
$repo_data = FS_Plugin_Updater::_fetch_plugin_info_from_repository(
|
193 |
-
'plugin_information', (object) array(
|
194 |
-
'slug' => $selected_addon->slug,
|
195 |
-
'is_ssl' => is_ssl(),
|
196 |
-
'fields' => array(
|
197 |
-
'banners' => true,
|
198 |
-
'reviews' => true,
|
199 |
-
'downloaded' => false,
|
200 |
-
'active_installs' => true
|
201 |
-
)
|
202 |
-
) );
|
203 |
-
|
204 |
-
if ( ! empty( $repo_data ) ) {
|
205 |
-
$data = $repo_data;
|
206 |
-
$data->wp_org_missing = false;
|
207 |
-
} else {
|
208 |
-
// Couldn't find plugin on .org.
|
209 |
-
$selected_addon->is_wp_org_compliant = false;
|
210 |
-
|
211 |
-
// Plugin is missing, not on Freemius nor WP.org.
|
212 |
-
$data->wp_org_missing = true;
|
213 |
-
}
|
214 |
-
|
215 |
-
$data->fs_missing = ( ! $has_free_plan || $data->wp_org_missing );
|
216 |
-
} else {
|
217 |
-
$data->has_purchased_license = false;
|
218 |
-
$data->wp_org_missing = false;
|
219 |
-
|
220 |
-
$fs_addon = null;
|
221 |
-
$current_addon_version = false;
|
222 |
-
if ( $this->_fs->is_addon_activated( $selected_addon->id ) ) {
|
223 |
-
$fs_addon = $this->_fs->get_addon_instance( $selected_addon->id );
|
224 |
-
$current_addon_version = $fs_addon->get_plugin_version();
|
225 |
-
} else if ( $this->_fs->is_addon_installed( $selected_addon->id ) ) {
|
226 |
-
$addon_plugin_data = get_plugin_data(
|
227 |
-
( WP_PLUGIN_DIR . '/' . $this->_fs->get_addon_basename( $selected_addon->id ) ),
|
228 |
-
false,
|
229 |
-
false
|
230 |
-
);
|
231 |
-
|
232 |
-
if ( ! empty( $addon_plugin_data ) ) {
|
233 |
-
$current_addon_version = $addon_plugin_data['Version'];
|
234 |
-
}
|
235 |
-
}
|
236 |
-
|
237 |
-
// Fetch latest version from Freemius.
|
238 |
-
$latest = $this->_fs->_fetch_latest_version(
|
239 |
-
$selected_addon->id,
|
240 |
-
true,
|
241 |
-
WP_FS__TIME_24_HOURS_IN_SEC,
|
242 |
-
$current_addon_version
|
243 |
-
);
|
244 |
-
|
245 |
-
if ( $has_paid_plan ) {
|
246 |
-
$blog_id = fs_request_get( 'fs_blog_id' );
|
247 |
-
$has_valid_blog_id = is_numeric( $blog_id );
|
248 |
-
|
249 |
-
if ( $has_valid_blog_id ) {
|
250 |
-
switch_to_blog( $blog_id );
|
251 |
-
}
|
252 |
-
|
253 |
-
$data->checkout_link = $this->_fs->checkout_url(
|
254 |
-
WP_FS__PERIOD_ANNUALLY,
|
255 |
-
false,
|
256 |
-
array(),
|
257 |
-
( $has_valid_blog_id ? false : null )
|
258 |
-
);
|
259 |
-
|
260 |
-
if ( $has_valid_blog_id ) {
|
261 |
-
restore_current_blog();
|
262 |
-
}
|
263 |
-
}
|
264 |
-
|
265 |
-
/**
|
266 |
-
* Check if there's a purchased license in case the add-on can only be installed/downloaded as part of a purchased bundle.
|
267 |
-
*
|
268 |
-
* @author Leo Fajardo (@leorw)
|
269 |
-
* @since 2.4.1
|
270 |
-
*/
|
271 |
-
if ( is_object( $fs_addon ) ) {
|
272 |
-
$data->has_purchased_license = $fs_addon->has_active_valid_license();
|
273 |
-
} else {
|
274 |
-
$account_addons = $this->_fs->get_account_addons();
|
275 |
-
if ( ! empty( $account_addons ) && in_array( $selected_addon->id, $account_addons ) ) {
|
276 |
-
$data->has_purchased_license = true;
|
277 |
-
}
|
278 |
-
}
|
279 |
-
|
280 |
-
if ( $has_free_plan || $data->has_purchased_license ) {
|
281 |
-
$data->download_link = $this->_fs->_get_latest_download_local_url( $selected_addon->id );
|
282 |
-
}
|
283 |
-
|
284 |
-
$data->fs_missing = (
|
285 |
-
false === $latest &&
|
286 |
-
(
|
287 |
-
empty( $selected_addon->premium_releases_count ) ||
|
288 |
-
! ( $selected_addon->premium_releases_count > 0 )
|
289 |
-
)
|
290 |
-
);
|
291 |
-
|
292 |
-
// Fetch as much as possible info from local files.
|
293 |
-
$plugin_local_data = $this->_fs->get_plugin_data();
|
294 |
-
$data->author = $plugin_local_data['Author'];
|
295 |
-
|
296 |
-
if ( ! empty( $selected_addon->info->banner_url ) ) {
|
297 |
-
$data->banners = array(
|
298 |
-
'low' => $selected_addon->info->banner_url,
|
299 |
-
);
|
300 |
-
}
|
301 |
-
|
302 |
-
if ( ! empty( $selected_addon->info->screenshots ) ) {
|
303 |
-
$view_vars = array(
|
304 |
-
'screenshots' => $selected_addon->info->screenshots,
|
305 |
-
'plugin' => $selected_addon,
|
306 |
-
);
|
307 |
-
$data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
|
308 |
-
}
|
309 |
-
|
310 |
-
if ( is_object( $latest ) ) {
|
311 |
-
$data->version = $latest->version;
|
312 |
-
$data->last_updated = $latest->created;
|
313 |
-
$data->requires = $latest->requires_platform_version;
|
314 |
-
$data->tested = $latest->tested_up_to_version;
|
315 |
-
} else if ( ! empty( $current_addon_version ) ) {
|
316 |
-
$data->version = $current_addon_version;
|
317 |
-
} else {
|
318 |
-
// Add dummy version.
|
319 |
-
$data->version = '1.0.0';
|
320 |
-
|
321 |
-
// Add message to developer to deploy the plugin through Freemius.
|
322 |
-
}
|
323 |
-
}
|
324 |
-
|
325 |
-
$data->name = $selected_addon->title;
|
326 |
-
$view_vars = array( 'plugin' => $selected_addon );
|
327 |
-
|
328 |
-
if ( is_object( $latest ) && isset( $latest->readme ) && is_object( $latest->readme ) ) {
|
329 |
-
$latest_version_readme_data = $latest->readme;
|
330 |
-
if ( isset( $latest_version_readme_data->sections ) ) {
|
331 |
-
$data->sections = (array) $latest_version_readme_data->sections;
|
332 |
-
} else {
|
333 |
-
$data->sections = array();
|
334 |
-
}
|
335 |
-
}
|
336 |
-
|
337 |
-
$data->sections['description'] = fs_get_template( '/plugin-info/description.php', $view_vars );
|
338 |
-
|
339 |
-
if ( $has_pricing ) {
|
340 |
-
// Add plans to data.
|
341 |
-
$data->plans = $plans;
|
342 |
-
|
343 |
-
if ( $has_features ) {
|
344 |
-
$view_vars = array(
|
345 |
-
'plans' => $plans,
|
346 |
-
'plugin' => $selected_addon,
|
347 |
-
);
|
348 |
-
$data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
|
349 |
-
}
|
350 |
-
}
|
351 |
-
|
352 |
-
$data->has_free_plan = $has_free_plan;
|
353 |
-
$data->has_paid_plan = $has_paid_plan;
|
354 |
-
$data->is_paid = $has_paid_plan;
|
355 |
-
$data->is_wp_org_compliant = $selected_addon->is_wp_org_compliant;
|
356 |
-
$data->premium_slug = $selected_addon->premium_slug;
|
357 |
-
$data->addon_id = $selected_addon->id;
|
358 |
-
|
359 |
-
if ( ! isset( $data->has_purchased_license ) ) {
|
360 |
-
$data->has_purchased_license = false;
|
361 |
-
}
|
362 |
-
|
363 |
-
return $data;
|
364 |
-
}
|
365 |
-
|
366 |
-
/**
|
367 |
-
* @author Vova Feldman (@svovaf)
|
368 |
-
* @since 1.1.7
|
369 |
-
*
|
370 |
-
* @param FS_Plugin_Plan $plan
|
371 |
-
*
|
372 |
-
* @return string
|
373 |
-
*/
|
374 |
-
private function get_billing_cycle( FS_Plugin_Plan $plan ) {
|
375 |
-
$billing_cycle = null;
|
376 |
-
|
377 |
-
if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) {
|
378 |
-
$pricing = $plan->pricing[0];
|
379 |
-
if ( isset( $pricing->annual_price ) ) {
|
380 |
-
$billing_cycle = 'annual';
|
381 |
-
} else if ( isset( $pricing->monthly_price ) ) {
|
382 |
-
$billing_cycle = 'monthly';
|
383 |
-
} else if ( isset( $pricing->lifetime_price ) ) {
|
384 |
-
$billing_cycle = 'lifetime';
|
385 |
-
}
|
386 |
-
} else {
|
387 |
-
foreach ( $plan->pricing as $pricing ) {
|
388 |
-
if ( isset( $pricing->annual_price ) ) {
|
389 |
-
$billing_cycle = 'annual';
|
390 |
-
} else if ( isset( $pricing->monthly_price ) ) {
|
391 |
-
$billing_cycle = 'monthly';
|
392 |
-
} else if ( isset( $pricing->lifetime_price ) ) {
|
393 |
-
$billing_cycle = 'lifetime';
|
394 |
-
}
|
395 |
-
|
396 |
-
if ( ! is_null( $billing_cycle ) ) {
|
397 |
-
break;
|
398 |
-
}
|
399 |
-
}
|
400 |
-
}
|
401 |
-
|
402 |
-
return $billing_cycle;
|
403 |
-
}
|
404 |
-
|
405 |
-
/**
|
406 |
-
* @author Vova Feldman (@svovaf)
|
407 |
-
* @since 2.0.0
|
408 |
-
*
|
409 |
-
* @param FS_Plugin_Plan $plan
|
410 |
-
* @param FS_Pricing $pricing
|
411 |
-
*
|
412 |
-
* @return float|null|string
|
413 |
-
*/
|
414 |
-
private function get_price_tag( FS_Plugin_Plan $plan, FS_Pricing $pricing ) {
|
415 |
-
$price_tag = '';
|
416 |
-
if ( isset( $pricing->annual_price ) ) {
|
417 |
-
$price_tag = $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
|
418 |
-
} else if ( isset( $pricing->monthly_price ) ) {
|
419 |
-
$price_tag = $pricing->monthly_price . ' / mo';
|
420 |
-
} else if ( isset( $pricing->lifetime_price ) ) {
|
421 |
-
$price_tag = $pricing->lifetime_price;
|
422 |
-
}
|
423 |
-
|
424 |
-
return '$' . $price_tag;
|
425 |
-
}
|
426 |
-
|
427 |
-
/**
|
428 |
-
* @author Leo Fajardo (@leorw)
|
429 |
-
* @since 2.3.0
|
430 |
-
*
|
431 |
-
* @param object $api
|
432 |
-
* @param FS_Plugin_Plan $plan
|
433 |
-
*
|
434 |
-
* @return string
|
435 |
-
*/
|
436 |
-
private function get_actions_dropdown( $api, $plan = null ) {
|
437 |
-
$this->actions = isset( $this->actions ) ?
|
438 |
-
$this->actions :
|
439 |
-
$this->get_plugin_actions( $api );
|
440 |
-
|
441 |
-
$actions = $this->actions;
|
442 |
-
|
443 |
-
$checkout_cta = $this->get_checkout_cta( $api, $plan );
|
444 |
-
if ( ! empty( $checkout_cta ) ) {
|
445 |
-
/**
|
446 |
-
* If there's no license yet, make the checkout button the main CTA. Otherwise, make it the last item in
|
447 |
-
* the actions dropdown.
|
448 |
-
*
|
449 |
-
* @author Leo Fajardo (@leorw)
|
450 |
-
* @since 2.3.0
|
451 |
-
*/
|
452 |
-
if ( ! $api->has_purchased_license ) {
|
453 |
-
array_unshift( $actions, $checkout_cta );
|
454 |
-
} else {
|
455 |
-
$actions[] = $checkout_cta;
|
456 |
-
}
|
457 |
-
}
|
458 |
-
|
459 |
-
if ( empty( $actions ) ) {
|
460 |
-
return '';
|
461 |
-
}
|
462 |
-
|
463 |
-
$total_actions = count( $actions );
|
464 |
-
if ( 1 === $total_actions ) {
|
465 |
-
return $actions[0];
|
466 |
-
}
|
467 |
-
|
468 |
-
ob_start();
|
469 |
-
|
470 |
-
?>
|
471 |
-
<div class="fs-cta fs-dropdown">
|
472 |
-
<div class="button-group">
|
473 |
-
<?php
|
474 |
-
// This should NOT be sanitized as the $actions are HTML buttons already.
|
475 |
-
echo $actions[0] ?>
|
476 |
-
<div class="button button-primary fs-dropdown-arrow-button">
|
477 |
-
<span class="fs-dropdown-arrow"></span>
|
478 |
-
<ul class="fs-dropdown-list" style="display: none">
|
479 |
-
<?php for ( $i = 1; $i < $total_actions; $i ++ ) : ?>
|
480 |
-
<li><?php echo str_replace( 'button button-primary', '', $actions[ $i ] ) ?></li>
|
481 |
-
<?php endfor ?>
|
482 |
-
</ul>
|
483 |
-
</div>
|
484 |
-
</div>
|
485 |
-
</div>
|
486 |
-
<?php
|
487 |
-
|
488 |
-
return ob_get_clean();
|
489 |
-
}
|
490 |
-
|
491 |
-
/**
|
492 |
-
* @author Vova Feldman (@svovaf)
|
493 |
-
* @since 1.1.7
|
494 |
-
*
|
495 |
-
* @param object $api
|
496 |
-
* @param FS_Plugin_Plan $plan
|
497 |
-
*
|
498 |
-
* @return string
|
499 |
-
*/
|
500 |
-
private function get_checkout_cta( $api, $plan = null ) {
|
501 |
-
if ( empty( $api->checkout_link ) ||
|
502 |
-
! isset( $api->plans ) ||
|
503 |
-
! is_array( $api->plans ) ||
|
504 |
-
0 == count( $api->plans )
|
505 |
-
) {
|
506 |
-
return '';
|
507 |
-
}
|
508 |
-
|
509 |
-
if ( is_null( $plan ) ) {
|
510 |
-
foreach ( $api->plans as $p ) {
|
511 |
-
if ( ! empty( $p->pricing ) ) {
|
512 |
-
$plan = $p;
|
513 |
-
break;
|
514 |
-
}
|
515 |
-
}
|
516 |
-
}
|
517 |
-
|
518 |
-
$blog_id = fs_request_get( 'fs_blog_id' );
|
519 |
-
$has_valid_blog_id = is_numeric( $blog_id );
|
520 |
-
|
521 |
-
if ( $has_valid_blog_id ) {
|
522 |
-
switch_to_blog( $blog_id );
|
523 |
-
}
|
524 |
-
|
525 |
-
$addon_checkout_url = $this->_fs->addon_checkout_url(
|
526 |
-
$plan->plugin_id,
|
527 |
-
$plan->pricing[0]->id,
|
528 |
-
$this->get_billing_cycle( $plan ),
|
529 |
-
$plan->has_trial(),
|
530 |
-
( $has_valid_blog_id ? false : null )
|
531 |
-
);
|
532 |
-
|
533 |
-
if ( $has_valid_blog_id ) {
|
534 |
-
restore_current_blog();
|
535 |
-
}
|
536 |
-
|
537 |
-
return '<a class="button button-primary fs-checkout-button right" href="' . $addon_checkout_url . '" target="_parent">' .
|
538 |
-
esc_html( ! $plan->has_trial() ?
|
539 |
-
(
|
540 |
-
$api->has_purchased_license ?
|
541 |
-
fs_text_inline( 'Purchase More', 'purchase-more', $api->slug ) :
|
542 |
-
fs_text_x_inline( 'Purchase', 'verb', 'purchase', $api->slug )
|
543 |
-
) :
|
544 |
-
sprintf(
|
545 |
-
/* translators: %s: N-days trial */
|
546 |
-
fs_text_inline( 'Start my free %s', 'start-free-x', $api->slug ),
|
547 |
-
$this->get_trial_period( $plan )
|
548 |
-
)
|
549 |
-
) .
|
550 |
-
'</a>';
|
551 |
-
}
|
552 |
-
|
553 |
-
/**
|
554 |
-
* @author Leo Fajardo (@leorw)
|
555 |
-
* @since 2.3.0
|
556 |
-
*
|
557 |
-
* @param object $api
|
558 |
-
*
|
559 |
-
* @return string[]
|
560 |
-
*/
|
561 |
-
private function get_plugin_actions( $api ) {
|
562 |
-
$this->status = isset( $this->status ) ?
|
563 |
-
$this->status :
|
564 |
-
install_plugin_install_status( $api );
|
565 |
-
|
566 |
-
$is_update_available = ( 'update_available' === $this->status['status'] );
|
567 |
-
|
568 |
-
if ( $is_update_available && empty( $this->status['url'] ) ) {
|
569 |
-
return array();
|
570 |
-
}
|
571 |
-
|
572 |
-
$blog_id = fs_request_get( 'fs_blog_id' );
|
573 |
-
|
574 |
-
$active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $blog_id );
|
575 |
-
|
576 |
-
$actions = array();
|
577 |
-
|
578 |
-
$is_addon_activated = $this->_fs->is_addon_activated( $api->slug );
|
579 |
-
$fs_addon = null;
|
580 |
-
|
581 |
-
$is_free_installed = null;
|
582 |
-
$is_premium_installed = null;
|
583 |
-
|
584 |
-
$has_installed_version = ( 'install' !== $this->status['status'] );
|
585 |
-
|
586 |
-
if ( ! $api->has_paid_plan && ! $api->has_purchased_license ) {
|
587 |
-
/**
|
588 |
-
* Free-only add-on.
|
589 |
-
*
|
590 |
-
* @author Leo Fajardo (@leorw)
|
591 |
-
* @since 2.3.0
|
592 |
-
*/
|
593 |
-
$is_free_installed = $has_installed_version;
|
594 |
-
$is_premium_installed = false;
|
595 |
-
} else if ( ! $api->has_free_plan ) {
|
596 |
-
/**
|
597 |
-
* Premium-only add-on.
|
598 |
-
*
|
599 |
-
* @author Leo Fajardo (@leorw)
|
600 |
-
* @since 2.3.0
|
601 |
-
*/
|
602 |
-
$is_free_installed = false;
|
603 |
-
$is_premium_installed = $has_installed_version;
|
604 |
-
} else {
|
605 |
-
/**
|
606 |
-
* Freemium add-on.
|
607 |
-
*
|
608 |
-
* @author Leo Fajardo (@leorw)
|
609 |
-
* @since 2.3.0
|
610 |
-
*/
|
611 |
-
if ( ! $has_installed_version ) {
|
612 |
-
$is_free_installed = false;
|
613 |
-
$is_premium_installed = false;
|
614 |
-
} else {
|
615 |
-
$fs_addon = $is_addon_activated ?
|
616 |
-
$this->_fs->get_addon_instance( $api->slug ) :
|
617 |
-
null;
|
618 |
-
|
619 |
-
if ( is_object( $fs_addon ) ) {
|
620 |
-
if ( $fs_addon->is_premium() ) {
|
621 |
-
$is_premium_installed = true;
|
622 |
-
} else {
|
623 |
-
$is_free_installed = true;
|
624 |
-
}
|
625 |
-
}
|
626 |
-
|
627 |
-
if ( is_null( $is_free_installed ) ) {
|
628 |
-
$is_free_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . "/{$api->slug}/{$api->slug}.php" ) );
|
629 |
-
if ( ! $is_free_installed ) {
|
630 |
-
/**
|
631 |
-
* Check if there's a plugin installed in a directory named `$api->slug`.
|
632 |
-
*
|
633 |
-
* @author Leo Fajardo (@leorw)
|
634 |
-
* @since 2.3.0
|
635 |
-
*/
|
636 |
-
$installed_plugins = get_plugins( '/' . $api->slug );
|
637 |
-
$is_free_installed = ( ! empty( $installed_plugins ) );
|
638 |
-
}
|
639 |
-
}
|
640 |
-
|
641 |
-
if ( is_null( $is_premium_installed ) ) {
|
642 |
-
$is_premium_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . "/{$api->premium_slug}/{$api->slug}.php" ) );
|
643 |
-
if ( ! $is_premium_installed ) {
|
644 |
-
/**
|
645 |
-
* Check if there's a plugin installed in a directory named `$api->premium_slug`.
|
646 |
-
*
|
647 |
-
* @author Leo Fajardo (@leorw)
|
648 |
-
* @since 2.3.0
|
649 |
-
*/
|
650 |
-
$installed_plugins = get_plugins( '/' . $api->premium_slug );
|
651 |
-
$is_premium_installed = ( ! empty( $installed_plugins ) );
|
652 |
-
}
|
653 |
-
}
|
654 |
-
}
|
655 |
-
|
656 |
-
$has_installed_version = ( $is_free_installed || $is_premium_installed );
|
657 |
-
}
|
658 |
-
|
659 |
-
$this->status['is_free_installed'] = $is_free_installed;
|
660 |
-
$this->status['is_premium_installed'] = $is_premium_installed;
|
661 |
-
|
662 |
-
$can_install_free_version = false;
|
663 |
-
$can_install_free_version_update = false;
|
664 |
-
$can_download_free_version = false;
|
665 |
-
$can_activate_free_version = false;
|
666 |
-
$can_install_premium_version = false;
|
667 |
-
$can_install_premium_version_update = false;
|
668 |
-
$can_download_premium_version = false;
|
669 |
-
$can_activate_premium_version = false;
|
670 |
-
|
671 |
-
if ( ! $api->has_purchased_license ) {
|
672 |
-
if ( $api->has_free_plan ) {
|
673 |
-
if ( $has_installed_version ) {
|
674 |
-
if ( $is_update_available ) {
|
675 |
-
$can_install_free_version_update = true;
|
676 |
-
} else if ( ! $is_premium_installed && ! isset( $active_plugins_directories_map[ dirname( $this->status['file'] ) ] ) ) {
|
677 |
-
$can_activate_free_version = true;
|
678 |
-
}
|
679 |
-
} else {
|
680 |
-
if (
|
681 |
-
$this->_fs->is_premium() ||
|
682 |
-
! $this->_fs->is_org_repo_compliant() ||
|
683 |
-
$api->is_wp_org_compliant
|
684 |
-
) {
|
685 |
-
$can_install_free_version = true;
|
686 |
-
} else {
|
687 |
-
$can_download_free_version = true;
|
688 |
-
}
|
689 |
-
}
|
690 |
-
}
|
691 |
-
} else {
|
692 |
-
if ( ! is_object( $fs_addon ) && $is_addon_activated ) {
|
693 |
-
$fs_addon = $this->_fs->get_addon_instance( $api->slug );
|
694 |
-
}
|
695 |
-
|
696 |
-
$can_download_premium_version = true;
|
697 |
-
|
698 |
-
if ( ! isset( $active_plugins_directories_map[ dirname( $this->status['file'] ) ] ) ) {
|
699 |
-
if ( $is_premium_installed ) {
|
700 |
-
$can_activate_premium_version = ( ! $is_addon_activated || ! $fs_addon->is_premium() );
|
701 |
-
} else if ( $is_free_installed ) {
|
702 |
-
$can_activate_free_version = ( ! $is_addon_activated );
|
703 |
-
}
|
704 |
-
}
|
705 |
-
|
706 |
-
if ( $this->_fs->is_premium() || ! $this->_fs->is_org_repo_compliant() ) {
|
707 |
-
if ( $is_update_available ) {
|
708 |
-
$can_install_premium_version_update = true;
|
709 |
-
} else if ( ! $is_premium_installed ) {
|
710 |
-
$can_install_premium_version = true;
|
711 |
-
}
|
712 |
-
}
|
713 |
-
}
|
714 |
-
|
715 |
-
if (
|
716 |
-
$can_install_premium_version ||
|
717 |
-
$can_install_premium_version_update
|
718 |
-
) {
|
719 |
-
if ( is_numeric( $blog_id ) ) {
|
720 |
-
/**
|
721 |
-
* Replace the network status URL with a blog admin–based status URL if the `Add-Ons` page is loaded
|
722 |
-
* from a specific blog admin page (when `fs_blog_id` is valid) in order for plugin installation/update
|
723 |
-
* to work.
|
724 |
-
*
|
725 |
-
* @author Leo Fajardo (@leorw)
|
726 |
-
* @since 2.3.0
|
727 |
-
*/
|
728 |
-
$this->status['url'] = self::get_blog_status_url( $blog_id, $this->status['url'], $this->status['status'] );
|
729 |
-
}
|
730 |
-
|
731 |
-
/**
|
732 |
-
* Add the `fs_allow_updater_and_dialog` param to the install/update URL so that the add-on can be
|
733 |
-
* installed/updated.
|
734 |
-
*
|
735 |
-
* @author Leo Fajardo (@leorw)
|
736 |
-
* @since 2.3.0
|
737 |
-
*/
|
738 |
-
$this->status['url'] = str_replace( '?', '?fs_allow_updater_and_dialog=true&', $this->status['url'] );
|
739 |
-
}
|
740 |
-
|
741 |
-
if ( $can_install_free_version_update || $can_install_premium_version_update ) {
|
742 |
-
$actions[] = $this->get_cta(
|
743 |
-
( $can_install_free_version_update ?
|
744 |
-
fs_esc_html_inline( 'Install Free Version Update Now', 'install-free-version-update-now', $api->slug ) :
|
745 |
-
fs_esc_html_inline( 'Install Update Now', 'install-update-now', $api->slug ) ),
|
746 |
-
true,
|
747 |
-
false,
|
748 |
-
$this->status['url'],
|
749 |
-
'_parent'
|
750 |
-
);
|
751 |
-
} else if ( $can_install_free_version || $can_install_premium_version ) {
|
752 |
-
$actions[] = $this->get_cta(
|
753 |
-
( $can_install_free_version ?
|
754 |
-
fs_esc_html_inline( 'Install Free Version Now', 'install-free-version-now', $api->slug ) :
|
755 |
-
fs_esc_html_inline( 'Install Now', 'install-now', $api->slug ) ),
|
756 |
-
true,
|
757 |
-
false,
|
758 |
-
$this->status['url'],
|
759 |
-
'_parent'
|
760 |
-
);
|
761 |
-
}
|
762 |
-
|
763 |
-
$download_latest_action = '';
|
764 |
-
|
765 |
-
if (
|
766 |
-
! empty( $api->download_link ) &&
|
767 |
-
( $can_download_free_version || $can_download_premium_version )
|
768 |
-
) {
|
769 |
-
$download_latest_action = $this->get_cta(
|
770 |
-
( $can_download_free_version ?
|
771 |
-
fs_esc_html_x_inline( 'Download Latest Free Version', 'as download latest version', 'download-latest-free-version', $api->slug ) :
|
772 |
-
fs_esc_html_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $api->slug ) ),
|
773 |
-
true,
|
774 |
-
false,
|
775 |
-
esc_url( $api->download_link )
|
776 |
-
);
|
777 |
-
}
|
778 |
-
|
779 |
-
if ( ! $can_activate_free_version && ! $can_activate_premium_version ) {
|
780 |
-
if ( ! empty( $download_latest_action ) ) {
|
781 |
-
$actions[] = $download_latest_action;
|
782 |
-
}
|
783 |
-
} else {
|
784 |
-
$activate_action = sprintf(
|
785 |
-
'<a class="button button-primary edit" href="%s" title="%s" target="_parent">%s</a>',
|
786 |
-
wp_nonce_url( ( is_numeric( $blog_id ) ? trailingslashit( get_admin_url( $blog_id ) ) : '' ) . 'plugins.php?action=activate&plugin=' . $this->status['file'], 'activate-plugin_' . $this->status['file'] ),
|
787 |
-
fs_esc_attr_inline( 'Activate this add-on', 'activate-this-addon', $api->slug ),
|
788 |
-
$can_activate_free_version ?
|
789 |
-
fs_text_inline( 'Activate Free Version', 'activate-free', $api->slug ) :
|
790 |
-
fs_text_inline( 'Activate', 'activate', $api->slug )
|
791 |
-
);
|
792 |
-
|
793 |
-
if ( ! $can_download_premium_version && ! empty( $download_latest_action ) ) {
|
794 |
-
$actions[] = $download_latest_action;
|
795 |
-
|
796 |
-
$download_latest_action = '';
|
797 |
-
}
|
798 |
-
|
799 |
-
if ( $can_install_premium_version || $can_install_premium_version_update ) {
|
800 |
-
if ( $can_download_premium_version && ! empty( $download_latest_action ) ) {
|
801 |
-
$actions[] = $download_latest_action;
|
802 |
-
|
803 |
-
$download_latest_action = '';
|
804 |
-
}
|
805 |
-
|
806 |
-
$actions[] = $activate_action;
|
807 |
-
} else {
|
808 |
-
array_unshift( $actions, $activate_action );
|
809 |
-
}
|
810 |
-
|
811 |
-
if ( ! empty ($download_latest_action ) ) {
|
812 |
-
$actions[] = $download_latest_action;
|
813 |
-
}
|
814 |
-
}
|
815 |
-
|
816 |
-
return $actions;
|
817 |
-
}
|
818 |
-
|
819 |
-
/**
|
820 |
-
* Rebuilds the status URL based on the admin URL.
|
821 |
-
*
|
822 |
-
* @author Leo Fajardo (@leorw)
|
823 |
-
* @since 2.3.0
|
824 |
-
*
|
825 |
-
* @param int $blog_id
|
826 |
-
* @param string $network_status_url
|
827 |
-
* @param string $status
|
828 |
-
*
|
829 |
-
* @return string
|
830 |
-
*/
|
831 |
-
private static function get_blog_status_url( $blog_id, $network_status_url, $status ) {
|
832 |
-
if ( ! in_array( $status, array( 'install', 'update_available' ) ) ) {
|
833 |
-
return $network_status_url;
|
834 |
-
}
|
835 |
-
|
836 |
-
$action = ( 'install' === $status ) ?
|
837 |
-
'install-plugin' :
|
838 |
-
'upgrade-plugin';
|
839 |
-
|
840 |
-
$query = parse_url( $network_status_url, PHP_URL_QUERY );
|
841 |
-
if ( empty( $query ) ) {
|
842 |
-
return $network_status_url;
|
843 |
-
}
|
844 |
-
|
845 |
-
parse_str( html_entity_decode( $query ), $url_params );
|
846 |
-
if ( empty( $url_params ) || ! isset( $url_params['plugin'] ) ) {
|
847 |
-
return $network_status_url;
|
848 |
-
}
|
849 |
-
|
850 |
-
$plugin = $url_params['plugin'];
|
851 |
-
|
852 |
-
return wp_nonce_url( get_admin_url( $blog_id,"update.php?action={$action}&plugin={$plugin}"), "{$action}_{$plugin}");
|
853 |
-
}
|
854 |
-
|
855 |
-
/**
|
856 |
-
* Helper method to get a CTA button HTML.
|
857 |
-
*
|
858 |
-
* @author Vova Feldman (@svovaf)
|
859 |
-
* @since 2.0.0
|
860 |
-
*
|
861 |
-
* @param string $label
|
862 |
-
* @param bool $is_primary
|
863 |
-
* @param bool $is_disabled
|
864 |
-
* @param string $href
|
865 |
-
* @param string $target
|
866 |
-
*
|
867 |
-
* @return string
|
868 |
-
*/
|
869 |
-
private function get_cta(
|
870 |
-
$label,
|
871 |
-
$is_primary = true,
|
872 |
-
$is_disabled = false,
|
873 |
-
$href = '',
|
874 |
-
$target = '_blank'
|
875 |
-
) {
|
876 |
-
$classes = array();
|
877 |
-
|
878 |
-
if ( ! $is_primary ) {
|
879 |
-
$classes[] = 'left';
|
880 |
-
} else {
|
881 |
-
$classes[] = 'button-primary';
|
882 |
-
$classes[] = 'right';
|
883 |
-
}
|
884 |
-
|
885 |
-
if ( $is_disabled ) {
|
886 |
-
$classes[] = 'disabled';
|
887 |
-
}
|
888 |
-
|
889 |
-
$rel = ( '_blank' === $target ) ? ' rel="noopener noreferrer"' : '';
|
890 |
-
|
891 |
-
return sprintf(
|
892 |
-
'<a %s class="button %s">%s</a>',
|
893 |
-
empty( $href ) ? '' : 'href="' . $href . '" target="' . $target . '"' . $rel,
|
894 |
-
implode( ' ', $classes ),
|
895 |
-
$label
|
896 |
-
);
|
897 |
-
}
|
898 |
-
|
899 |
-
/**
|
900 |
-
* @author Vova Feldman (@svovaf)
|
901 |
-
* @since 1.1.7
|
902 |
-
*
|
903 |
-
* @param FS_Plugin_Plan $plan
|
904 |
-
*
|
905 |
-
* @return string
|
906 |
-
*/
|
907 |
-
private function get_trial_period( $plan ) {
|
908 |
-
$trial_period = (int) $plan->trial_period;
|
909 |
-
|
910 |
-
switch ( $trial_period ) {
|
911 |
-
case 30:
|
912 |
-
return 'month';
|
913 |
-
case 60:
|
914 |
-
return '2 months';
|
915 |
-
default:
|
916 |
-
return "{$plan->trial_period} days";
|
917 |
-
}
|
918 |
-
}
|
919 |
-
|
920 |
-
/**
|
921 |
-
* Display plugin information in dialog box form.
|
922 |
-
*
|
923 |
-
* Based on core install_plugin_information() function.
|
924 |
-
*
|
925 |
-
* @author Vova Feldman (@svovaf)
|
926 |
-
* @since 1.0.6
|
927 |
-
*/
|
928 |
-
function install_plugin_information() {
|
929 |
-
global $tab;
|
930 |
-
|
931 |
-
if ( empty( $_REQUEST['plugin'] ) ) {
|
932 |
-
return;
|
933 |
-
}
|
934 |
-
|
935 |
-
$args = array(
|
936 |
-
'slug' => wp_unslash( $_REQUEST['plugin'] ),
|
937 |
-
'is_ssl' => is_ssl(),
|
938 |
-
'fields' => array(
|
939 |
-
'banners' => true,
|
940 |
-
'reviews' => true,
|
941 |
-
'downloaded' => false,
|
942 |
-
'active_installs' => true
|
943 |
-
)
|
944 |
-
);
|
945 |
-
|
946 |
-
if ( is_array( $args ) ) {
|
947 |
-
$args = (object) $args;
|
948 |
-
}
|
949 |
-
|
950 |
-
if ( ! isset( $args->per_page ) ) {
|
951 |
-
$args->per_page = 24;
|
952 |
-
}
|
953 |
-
|
954 |
-
if ( ! isset( $args->locale ) ) {
|
955 |
-
$args->locale = get_locale();
|
956 |
-
}
|
957 |
-
|
958 |
-
$api = apply_filters( 'fs_plugins_api', false, 'plugin_information', $args );
|
959 |
-
|
960 |
-
if ( is_wp_error( $api ) ) {
|
961 |
-
wp_die( $api );
|
962 |
-
}
|
963 |
-
|
964 |
-
$plugins_allowedtags = array(
|
965 |
-
'a' => array(
|
966 |
-
'href' => array(),
|
967 |
-
'title' => array(),
|
968 |
-
'target' => array(),
|
969 |
-
// Add image style for screenshots.
|
970 |
-
'class' => array()
|
971 |
-
),
|
972 |
-
'style' => array(),
|
973 |
-
'abbr' => array( 'title' => array() ),
|
974 |
-
'acronym' => array( 'title' => array() ),
|
975 |
-
'code' => array(),
|
976 |
-
'pre' => array(),
|
977 |
-
'em' => array(),
|
978 |
-
'strong' => array(),
|
979 |
-
'div' => array( 'class' => array() ),
|
980 |
-
'span' => array( 'class' => array() ),
|
981 |
-
'p' => array(),
|
982 |
-
'ul' => array(),
|
983 |
-
'ol' => array(),
|
984 |
-
'li' => array( 'class' => array() ),
|
985 |
-
'i' => array( 'class' => array() ),
|
986 |
-
'h1' => array(),
|
987 |
-
'h2' => array(),
|
988 |
-
'h3' => array(),
|
989 |
-
'h4' => array(),
|
990 |
-
'h5' => array(),
|
991 |
-
'h6' => array(),
|
992 |
-
'img' => array( 'src' => array(), 'class' => array(), 'alt' => array() ),
|
993 |
-
// 'table' => array(),
|
994 |
-
// 'td' => array(),
|
995 |
-
// 'tr' => array(),
|
996 |
-
// 'th' => array(),
|
997 |
-
// 'thead' => array(),
|
998 |
-
// 'tbody' => array(),
|
999 |
-
);
|
1000 |
-
|
1001 |
-
$plugins_section_titles = array(
|
1002 |
-
'description' => fs_text_x_inline( 'Description', 'Plugin installer section title', 'description', $api->slug ),
|
1003 |
-
'installation' => fs_text_x_inline( 'Installation', 'Plugin installer section title', 'installation', $api->slug ),
|
1004 |
-
'faq' => fs_text_x_inline( 'FAQ', 'Plugin installer section title', 'faq', $api->slug ),
|
1005 |
-
'screenshots' => fs_text_inline( 'Screenshots', 'screenshots', $api->slug ),
|
1006 |
-
'changelog' => fs_text_x_inline( 'Changelog', 'Plugin installer section title', 'changelog', $api->slug ),
|
1007 |
-
'reviews' => fs_text_x_inline( 'Reviews', 'Plugin installer section title', 'reviews', $api->slug ),
|
1008 |
-
'other_notes' => fs_text_x_inline( 'Other Notes', 'Plugin installer section title', 'other-notes', $api->slug ),
|
1009 |
-
);
|
1010 |
-
|
1011 |
-
// Sanitize HTML
|
1012 |
-
// foreach ( (array) $api->sections as $section_name => $content ) {
|
1013 |
-
// $api->sections[$section_name] = wp_kses( $content, $plugins_allowedtags );
|
1014 |
-
// }
|
1015 |
-
|
1016 |
-
foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
|
1017 |
-
if ( isset( $api->$key ) ) {
|
1018 |
-
$api->$key = wp_kses( $api->$key, $plugins_allowedtags );
|
1019 |
-
}
|
1020 |
-
}
|
1021 |
-
|
1022 |
-
// Add after $api->slug is ready.
|
1023 |
-
$plugins_section_titles['features'] = fs_text_x_inline( 'Features & Pricing', 'Plugin installer section title', 'features-and-pricing', $api->slug );
|
1024 |
-
|
1025 |
-
$_tab = esc_attr( $tab );
|
1026 |
-
|
1027 |
-
$section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; // Default to the Description tab, Do not translate, API returns English.
|
1028 |
-
if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) {
|
1029 |
-
$section_titles = array_keys( (array) $api->sections );
|
1030 |
-
$section = array_shift( $section_titles );
|
1031 |
-
}
|
1032 |
-
|
1033 |
-
iframe_header( fs_text_inline( 'Plugin Install', 'plugin-install', $api->slug ) );
|
1034 |
-
|
1035 |
-
$_with_banner = '';
|
1036 |
-
|
1037 |
-
// var_dump($api->banners);
|
1038 |
-
if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) {
|
1039 |
-
$_with_banner = 'with-banner';
|
1040 |
-
$low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low'];
|
1041 |
-
$high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high'];
|
1042 |
-
?>
|
1043 |
-
<style type="text/css">
|
1044 |
-
#plugin-information-title.with-banner
|
1045 |
-
{
|
1046 |
-
background-image: url( <?php echo esc_url( $low ); ?> );
|
1047 |
-
}
|
1048 |
-
|
1049 |
-
@media only screen and ( -webkit-min-device-pixel-ratio: 1.5 )
|
1050 |
-
{
|
1051 |
-
#plugin-information-title.with-banner
|
1052 |
-
{
|
1053 |
-
background-image: url( <?php echo esc_url( $high ); ?> );
|
1054 |
-
}
|
1055 |
-
}
|
1056 |
-
</style>
|
1057 |
-
<?php
|
1058 |
-
}
|
1059 |
-
|
1060 |
-
echo '<div id="plugin-information-scrollable">';
|
1061 |
-
echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>";
|
1062 |
-
echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n";
|
1063 |
-
|
1064 |
-
foreach ( (array) $api->sections as $section_name => $content ) {
|
1065 |
-
if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) {
|
1066 |
-
continue;
|
1067 |
-
}
|
1068 |
-
|
1069 |
-
if ( isset( $plugins_section_titles[ $section_name ] ) ) {
|
1070 |
-
$title = $plugins_section_titles[ $section_name ];
|
1071 |
-
} else {
|
1072 |
-
$title = ucwords( str_replace( '_', ' ', $section_name ) );
|
1073 |
-
}
|
1074 |
-
|
1075 |
-
$class = ( $section_name === $section ) ? ' class="current"' : '';
|
1076 |
-
$href = add_query_arg( array( 'tab' => $tab, 'section' => $section_name ) );
|
1077 |
-
$href = esc_url( $href );
|
1078 |
-
$san_section = esc_attr( $section_name );
|
1079 |
-
echo "\t<a name='$san_section' href='$href' $class>" . esc_html( $title ) . "</a>\n";
|
1080 |
-
}
|
1081 |
-
|
1082 |
-
echo "</div>\n";
|
1083 |
-
|
1084 |
-
?>
|
1085 |
-
<div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'>
|
1086 |
-
<div class="fyi">
|
1087 |
-
<?php if ( $api->is_paid ) : ?>
|
1088 |
-
<?php if ( isset( $api->plans ) ) : ?>
|
1089 |
-
<div class="plugin-information-pricing">
|
1090 |
-
<?php foreach ( $api->plans as $plan ) : ?>
|
1091 |
-
<?php
|
1092 |
-
if ( empty( $plan->pricing ) ) {
|
1093 |
-
continue;
|
1094 |
-
}
|
1095 |
-
|
1096 |
-
/**
|
1097 |
-
* @var FS_Plugin_Plan $plan
|
1098 |
-
*/
|
1099 |
-
?>
|
1100 |
-
<?php $first_pricing = $plan->pricing[0] ?>
|
1101 |
-
<?php $is_multi_cycle = $first_pricing->is_multi_cycle() ?>
|
1102 |
-
<div class="fs-plan<?php if ( ! $is_multi_cycle ) {
|
1103 |
-
echo ' fs-single-cycle';
|
1104 |
-
} ?>" data-plan-id="<?php echo $plan->id ?>">
|
1105 |
-
<h3 data-plan="<?php echo $plan->id ?>"><?php echo esc_html( sprintf( fs_text_x_inline( '%s Plan', 'e.g. Professional Plan', 'x-plan', $api->slug ), $plan->title ) ) ?></h3>
|
1106 |
-
<?php $has_annual = $first_pricing->has_annual() ?>
|
1107 |
-
<?php $has_monthly = $first_pricing->has_monthly() ?>
|
1108 |
-
<div class="nav-tab-wrapper">
|
1109 |
-
<?php $billing_cycles = array( 'monthly', 'annual', 'lifetime' ) ?>
|
1110 |
-
<?php $i = 0;
|
1111 |
-
foreach ( $billing_cycles as $cycle ) : ?>
|
1112 |
-
<?php $prop = "{$cycle}_price";
|
1113 |
-
if ( isset( $first_pricing->{$prop} ) ) : ?>
|
1114 |
-
<?php $is_featured = ( 'annual' === $cycle && $is_multi_cycle ) ?>
|
1115 |
-
<?php
|
1116 |
-
$prices = array();
|
1117 |
-
foreach ( $plan->pricing as $pricing ) {
|
1118 |
-
if ( isset( $pricing->{$prop} ) ) {
|
1119 |
-
$prices[] = array(
|
1120 |
-
'id' => $pricing->id,
|
1121 |
-
'licenses' => $pricing->licenses,
|
1122 |
-
'price' => $pricing->{$prop}
|
1123 |
-
);
|
1124 |
-
}
|
1125 |
-
}
|
1126 |
-
?>
|
1127 |
-
<a class="nav-tab" data-billing-cycle="<?php echo $cycle ?>"
|
1128 |
-
data-pricing="<?php echo esc_attr( json_encode( $prices ) ) ?>">
|
1129 |
-
<?php if ( $is_featured ) : ?>
|
1130 |
-
<label>
|
1131 |
-
★ <?php fs_esc_html_echo_x_inline( 'Best', 'e.g. the best product', 'best', $api->slug ) ?>
|
1132 |
-
★</label>
|
1133 |
-
<?php endif ?>
|
1134 |
-
<?php
|
1135 |
-
switch ( $cycle ) {
|
1136 |
-
case 'monthly':
|
1137 |
-
fs_esc_html_echo_x_inline( 'Monthly', 'as every month', 'monthly', $api->slug );
|
1138 |
-
break;
|
1139 |
-
case 'annual':
|
1140 |
-
fs_esc_html_echo_x_inline( 'Annual', 'as once a year', 'annual', $api->slug );
|
1141 |
-
break;
|
1142 |
-
case 'lifetime':
|
1143 |
-
fs_esc_html_echo_inline( 'Lifetime', 'lifetime', $api->slug );
|
1144 |
-
break;
|
1145 |
-
}
|
1146 |
-
?>
|
1147 |
-
</a>
|
1148 |
-
<?php endif ?>
|
1149 |
-
<?php $i ++; endforeach ?>
|
1150 |
-
<?php wp_enqueue_script( 'jquery' ) ?>
|
1151 |
-
<script type="text/javascript">
|
1152 |
-
(function ($, undef) {
|
1153 |
-
var
|
1154 |
-
_formatBillingFrequency = function (cycle) {
|
1155 |
-
switch (cycle) {
|
1156 |
-
case 'monthly':
|
1157 |
-
return '<?php printf( fs_text_x_inline( 'Billed %s', 'e.g. billed monthly', 'billed-x', $api->slug ), fs_text_x_inline( 'Monthly', 'as every month', 'monthly', $api->slug ) ) ?>';
|
1158 |
-
case 'annual':
|
1159 |
-
return '<?php printf( fs_text_x_inline( 'Billed %s', 'e.g. billed monthly', 'billed-x', $api->slug ), fs_text_x_inline( 'Annually', 'as once a year', 'annually', $api->slug ) ) ?>';
|
1160 |
-
case 'lifetime':
|
1161 |
-
return '<?php printf( fs_text_x_inline( 'Billed %s', 'e.g. billed monthly', 'billed-x', $api->slug ), fs_text_x_inline( 'Once', 'as once a year', 'once', $api->slug ) ) ?>';
|
1162 |
-
}
|
1163 |
-
},
|
1164 |
-
_formatLicensesTitle = function (pricing) {
|
1165 |
-
switch (pricing.licenses) {
|
1166 |
-
case 1:
|
1167 |
-
return '<?php fs_esc_attr_echo_inline( 'Single Site License', 'license-single-site', $api->slug ) ?>';
|
1168 |
-
case null:
|
1169 |
-
return '<?php fs_esc_attr_echo_inline( 'Unlimited Licenses', 'license-unlimited', $api->slug ) ?>';
|
1170 |
-
default:
|
1171 |
-
return '<?php fs_esc_attr_echo_inline( 'Up to %s Sites', 'license-x-sites', $api->slug ) ?>'.replace('%s', pricing.licenses);
|
1172 |
-
}
|
1173 |
-
},
|
1174 |
-
_formatPrice = function (pricing, cycle, multipleLicenses) {
|
1175 |
-
if (undef === multipleLicenses)
|
1176 |
-
multipleLicenses = true;
|
1177 |
-
|
1178 |
-
var priceCycle;
|
1179 |
-
switch (cycle) {
|
1180 |
-
case 'monthly':
|
1181 |
-
priceCycle = ' / <?php fs_echo_x_inline( 'mo', 'as monthly period', 'mo', $api->slug ) ?>';
|
1182 |
-
break;
|
1183 |
-
case 'lifetime':
|
1184 |
-
priceCycle = '';
|
1185 |
-
break;
|
1186 |
-
case 'annual':
|
1187 |
-
default:
|
1188 |
-
priceCycle = ' / <?php fs_echo_x_inline( 'year', 'as annual period', 'year', $api->slug ) ?>';
|
1189 |
-
break;
|
1190 |
-
}
|
1191 |
-
|
1192 |
-
if (!multipleLicenses && 1 == pricing.licenses) {
|
1193 |
-
return '$' + pricing.price + priceCycle;
|
1194 |
-
}
|
1195 |
-
|
1196 |
-
return _formatLicensesTitle(pricing) + ' - <var class="fs-price">$' + pricing.price + priceCycle + '</var>';
|
1197 |
-
},
|
1198 |
-
_checkoutUrl = function (plan, pricing, cycle) {
|
1199 |
-
return '<?php echo esc_url_raw( remove_query_arg( 'billing_cycle', add_query_arg( array( 'plugin_id' => $plan->plugin_id ), $api->checkout_link ) ) ) ?>' +
|
1200 |
-
'&plan_id=' + plan +
|
1201 |
-
'&pricing_id=' + pricing +
|
1202 |
-
'&billing_cycle=' + cycle<?php if ( $plan->has_trial() ) {
|
1203 |
-
echo " + '&trial=true'";
|
1204 |
-
}?>;
|
1205 |
-
},
|
1206 |
-
_updateCtaUrl = function (plan, pricing, cycle) {
|
1207 |
-
$('.plugin-information-pricing .fs-checkout-button, #plugin-information-footer .fs-checkout-button').attr('href', _checkoutUrl(plan, pricing, cycle));
|
1208 |
-
};
|
1209 |
-
|
1210 |
-
$(document).ready(function () {
|
1211 |
-
var $plan = $('.plugin-information-pricing .fs-plan[data-plan-id=<?php echo $plan->id ?>]');
|
1212 |
-
$plan.find('input[type=radio]').on('click', function () {
|
1213 |
-
_updateCtaUrl(
|
1214 |
-
$plan.attr('data-plan-id'),
|
1215 |
-
$(this).val(),
|
1216 |
-
$plan.find('.nav-tab-active').attr('data-billing-cycle')
|
1217 |
-
);
|
1218 |
-
|
1219 |
-
$plan.find('.fs-trial-terms .fs-price').html(
|
1220 |
-
$(this).parents('label').find('.fs-price').html()
|
1221 |
-
);
|
1222 |
-
});
|
1223 |
-
|
1224 |
-
$plan.find('.nav-tab').click(function () {
|
1225 |
-
if ($(this).hasClass('nav-tab-active'))
|
1226 |
-
return;
|
1227 |
-
|
1228 |
-
var $this = $(this),
|
1229 |
-
billingCycle = $this.attr('data-billing-cycle'),
|
1230 |
-
pricing = JSON.parse($this.attr('data-pricing')),
|
1231 |
-
$pricesList = $this.parents('.fs-plan').find('.fs-pricing-body .fs-licenses'),
|
1232 |
-
html = '';
|
1233 |
-
|
1234 |
-
// Un-select previously selected tab.
|
1235 |
-
$plan.find('.nav-tab').removeClass('nav-tab-active');
|
1236 |
-
|
1237 |
-
// Select current tab.
|
1238 |
-
$this.addClass('nav-tab-active');
|
1239 |
-
|
1240 |
-
// Render licenses prices.
|
1241 |
-
if (1 == pricing.length) {
|
1242 |
-
html = '<li><label><?php echo fs_esc_attr_x_inline( 'Price', 'noun', 'price', $api->slug ) ?>: ' + _formatPrice(pricing[0], billingCycle, false) + '</label></li>';
|
1243 |
-
} else {
|
1244 |
-
for (var i = 0; i < pricing.length; i++) {
|
1245 |
-
html += '<li><label><input name="pricing-<?php echo $plan->id ?>" type="radio" value="' + pricing[i].id + '">' + _formatPrice(pricing[i], billingCycle) + '</label></li>';
|
1246 |
-
}
|
1247 |
-
}
|
1248 |
-
$pricesList.html(html);
|
1249 |
-
|
1250 |
-
if (1 < pricing.length) {
|
1251 |
-
// Select first license option.
|
1252 |
-
$pricesList.find('li:first input').click();
|
1253 |
-
}
|
1254 |
-
else {
|
1255 |
-
_updateCtaUrl(
|
1256 |
-
$plan.attr('data-plan-id'),
|
1257 |
-
pricing[0].id,
|
1258 |
-
billingCycle
|
1259 |
-
);
|
1260 |
-
}
|
1261 |
-
|
1262 |
-
// Update billing frequency.
|
1263 |
-
$plan.find('.fs-billing-frequency').html(_formatBillingFrequency(billingCycle));
|
1264 |
-
|
1265 |
-
if ('annual' === billingCycle) {
|
1266 |
-
$plan.find('.fs-annual-discount').show();
|
1267 |
-
} else {
|
1268 |
-
$plan.find('.fs-annual-discount').hide();
|
1269 |
-
}
|
1270 |
-
});
|
1271 |
-
|
1272 |
-
<?php if ( $has_annual ) : ?>
|
1273 |
-
// Select annual by default.
|
1274 |
-
$plan.find('.nav-tab[data-billing-cycle=annual]').click();
|
1275 |
-
<?php else : ?>
|
1276 |
-
// Select first tab.
|
1277 |
-
$plan.find('.nav-tab:first').click();
|
1278 |
-
<?php endif ?>
|
1279 |
-
});
|
1280 |
-
}(jQuery));
|
1281 |
-
</script>
|
1282 |
-
</div>
|
1283 |
-
<div class="fs-pricing-body">
|
1284 |
-
<span class="fs-billing-frequency"></span>
|
1285 |
-
<?php $annual_discount = ( $has_annual && $has_monthly ) ? $plan->pricing[0]->annual_discount_percentage() : 0 ?>
|
1286 |
-
<?php if ( $annual_discount > 0 ) : ?>
|
1287 |
-
<span
|
1288 |
-
class="fs-annual-discount"><?php printf(
|
1289 |
-
/* translators: %s: Discount (e.g. discount of $5 or 10%) */
|
1290 |
-
fs_esc_html_inline( 'Save %s', 'save-x', $api->slug ), $annual_discount . '%' ) ?></span>
|
1291 |
-
<?php endif ?>
|
1292 |
-
<ul class="fs-licenses">
|
1293 |
-
</ul>
|
1294 |
-
<?php echo $this->get_actions_dropdown( $api, $plan ) ?>
|
1295 |
-
<div style="clear:both"></div>
|
1296 |
-
<?php if ( $plan->has_trial() ) : ?>
|
1297 |
-
<?php $trial_period = $this->get_trial_period( $plan ) ?>
|
1298 |
-
<ul class="fs-trial-terms">
|
1299 |
-
<li>
|
1300 |
-
<i class="dashicons dashicons-yes"></i><?php echo esc_html( sprintf( fs_text_inline( 'No commitment for %s - cancel anytime', 'no-commitment-x', $api->slug ), $trial_period ) ) ?>
|
1301 |
-
</li>
|
1302 |
-
<li>
|
1303 |
-
<i class="dashicons dashicons-yes"></i><?php printf( esc_html( fs_text_inline( 'After your free %s, pay as little as %s', 'after-x-pay-as-little-y', $api->slug ) ), $trial_period, '<var class="fs-price">' . $this->get_price_tag( $plan, $plan->pricing[0] ) . '</var>' ) ?>
|
1304 |
-
</li>
|
1305 |
-
</ul>
|
1306 |
-
<?php endif ?>
|
1307 |
-
</div>
|
1308 |
-
</div>
|
1309 |
-
</div>
|
1310 |
-
<?php endforeach ?>
|
1311 |
-
<?php endif ?>
|
1312 |
-
<?php endif ?>
|
1313 |
-
<div>
|
1314 |
-
<h3><?php fs_echo_inline( 'Details', 'details', $api->slug ) ?></h3>
|
1315 |
-
<ul>
|
1316 |
-
<?php if ( ! empty( $api->version ) ) { ?>
|
1317 |
-
<li>
|
1318 |
-
<strong><?php fs_esc_html_echo_x_inline( 'Version', 'product version', 'version', $api->slug ); ?>
|
1319 |
-
:</strong> <?php echo $api->version; ?></li>
|
1320 |
-
<?php
|
1321 |
-
}
|
1322 |
-
if ( ! empty( $api->author ) ) {
|
1323 |
-
?>
|
1324 |
-
<li>
|
1325 |
-
<strong><?php fs_echo_x_inline( 'Author', 'as the plugin author', 'author', $api->slug ); ?>
|
1326 |
-
:</strong> <?php echo links_add_target( $api->author, '_blank' ); ?>
|
1327 |
-
</li>
|
1328 |
-
<?php
|
1329 |
-
}
|
1330 |
-
if ( ! empty( $api->last_updated ) ) {
|
1331 |
-
?>
|
1332 |
-
<li><strong><?php fs_echo_inline( 'Last Updated', 'last-updated', $api->slug ); ?>
|
1333 |
-
:</strong> <span
|
1334 |
-
title="<?php echo $api->last_updated; ?>">
|
1335 |
-
<?php echo esc_html( sprintf(
|
1336 |
-
/* translators: %s: time period (e.g. "2 hours" ago) */
|
1337 |
-
fs_text_x_inline( '%s ago', 'x-ago', $api->slug ),
|
1338 |
-
human_time_diff( strtotime( $api->last_updated ) )
|
1339 |
-
) ) ?>
|
1340 |
-
</span></li>
|
1341 |
-
<?php
|
1342 |
-
}
|
1343 |
-
if ( ! empty( $api->requires ) ) {
|
1344 |
-
?>
|
1345 |
-
<li>
|
1346 |
-
<strong><?php fs_esc_html_echo_inline( 'Requires WordPress Version', 'requires-wordpress-version', $api->slug ) ?>
|
1347 |
-
:</strong> <?php echo esc_html( sprintf( fs_text_inline( '%s or higher', 'x-or-higher', $api->slug ), $api->requires ) ) ?>
|
1348 |
-
</li>
|
1349 |
-
<?php
|
1350 |
-
}
|
1351 |
-
if ( ! empty( $api->tested ) ) {
|
1352 |
-
?>
|
1353 |
-
<li>
|
1354 |
-
<strong><?php fs_esc_html_echo_inline( 'Compatible up to', 'compatible-up-to', $api->slug ); ?>
|
1355 |
-
:</strong> <?php echo $api->tested; ?>
|
1356 |
-
</li>
|
1357 |
-
<?php
|
1358 |
-
}
|
1359 |
-
if ( ! empty( $api->downloaded ) ) {
|
1360 |
-
?>
|
1361 |
-
<li>
|
1362 |
-
<strong><?php fs_esc_html_echo_inline( 'Downloaded', 'downloaded', $api->slug ) ?>
|
1363 |
-
:</strong> <?php echo esc_html( sprintf(
|
1364 |
-
( ( 1 == $api->downloaded ) ?
|
1365 |
-
/* translators: %s: 1 or One (Number of times downloaded) */
|
1366 |
-
fs_text_inline( '%s time', 'x-time', $api->slug ) :
|
1367 |
-
/* translators: %s: Number of times downloaded */
|
1368 |
-
fs_text_inline( '%s times', 'x-times', $api->slug )
|
1369 |
-
),
|
1370 |
-
number_format_i18n( $api->downloaded )
|
1371 |
-
) ); ?>
|
1372 |
-
</li>
|
1373 |
-
<?php
|
1374 |
-
}
|
1375 |
-
if ( ! empty( $api->slug ) && true == $api->is_wp_org_compliant ) {
|
1376 |
-
?>
|
1377 |
-
<li><a target="_blank"
|
1378 |
-
rel="noopener noreferrer"
|
1379 |
-
href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php fs_esc_html_echo_inline( 'WordPress.org Plugin Page', 'wp-org-plugin-page', $api->slug ) ?>
|
1380 |
-
»</a>
|
1381 |
-
</li>
|
1382 |
-
<?php
|
1383 |
-
}
|
1384 |
-
if ( ! empty( $api->homepage ) ) {
|
1385 |
-
?>
|
1386 |
-
<li><a target="_blank"
|
1387 |
-
rel="noopener noreferrer"
|
1388 |
-
href="<?php echo esc_url( $api->homepage ); ?>"><?php fs_esc_html_echo_inline( 'Plugin Homepage', 'plugin-homepage', $api->slug ) ?>
|
1389 |
-
»</a>
|
1390 |
-
</li>
|
1391 |
-
<?php
|
1392 |
-
}
|
1393 |
-
if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) {
|
1394 |
-
?>
|
1395 |
-
<li><a target="_blank"
|
1396 |
-
rel="noopener noreferrer"
|
1397 |
-
href="<?php echo esc_url( $api->donate_link ); ?>"><?php fs_esc_html_echo_inline( 'Donate to this plugin', 'donate-to-plugin', $api->slug ) ?>
|
1398 |
-
»</a>
|
1399 |
-
</li>
|
1400 |
-
<?php } ?>
|
1401 |
-
</ul>
|
1402 |
-
</div>
|
1403 |
-
<?php if ( ! empty( $api->rating ) ) { ?>
|
1404 |
-
<h3><?php fs_echo_inline( 'Average Rating', 'average-rating', $api->slug ); ?></h3>
|
1405 |
-
<?php wp_star_rating( array(
|
1406 |
-
'rating' => $api->rating,
|
1407 |
-
'type' => 'percent',
|
1408 |
-
'number' => $api->num_ratings
|
1409 |
-
) ); ?>
|
1410 |
-
<small>(<?php echo esc_html( sprintf(
|
1411 |
-
fs_text_inline( 'based on %s', 'based-on-x', $api->slug ),
|
1412 |
-
sprintf(
|
1413 |
-
( ( 1 == $api->num_ratings ) ?
|
1414 |
-
/* translators: %s: 1 or One */
|
1415 |
-
fs_text_inline( '%s rating', 'x-rating', $api->slug ) :
|
1416 |
-
/* translators: %s: Number larger than 1 */
|
1417 |
-
fs_text_inline( '%s ratings', 'x-ratings', $api->slug )
|
1418 |
-
),
|
1419 |
-
number_format_i18n( $api->num_ratings )
|
1420 |
-
) ) ) ?>)
|
1421 |
-
</small>
|
1422 |
-
<?php
|
1423 |
-
}
|
1424 |
-
|
1425 |
-
if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) {
|
1426 |
-
foreach ( $api->ratings as $key => $ratecount ) {
|
1427 |
-
// Avoid div-by-zero.
|
1428 |
-
$_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0;
|
1429 |
-
$stars_label = sprintf(
|
1430 |
-
( ( 1 == $key ) ?
|
1431 |
-
/* translators: %s: 1 or One */
|
1432 |
-
fs_text_inline( '%s star', 'x-star', $api->slug ) :
|
1433 |
-
/* translators: %s: Number larger than 1 */
|
1434 |
-
fs_text_inline( '%s stars', 'x-stars', $api->slug )
|
1435 |
-
),
|
1436 |
-
number_format_i18n( $key )
|
1437 |
-
);
|
1438 |
-
?>
|
1439 |
-
<div class="counter-container">
|
1440 |
-
<span class="counter-label"><a
|
1441 |
-
href="https://wordpress.org/support/view/plugin-reviews/<?php echo $api->slug; ?>?filter=<?php echo $key; ?>"
|
1442 |
-
target="_blank"
|
1443 |
-
rel="noopener noreferrer"
|
1444 |
-
title="<?php echo esc_attr( sprintf(
|
1445 |
-
/* translators: %s: # of stars (e.g. 5 stars) */
|
1446 |
-
fs_text_inline( 'Click to see reviews that provided a rating of %s', 'click-to-reviews', $api->slug ),
|
1447 |
-
$stars_label
|
1448 |
-
) ) ?>"><?php echo $stars_label ?></a></span>
|
1449 |
-
<span class="counter-back">
|
1450 |
-
<span class="counter-bar" style="width: <?php echo absint(92 * $_rating); ?>px;"></span>
|
1451 |
-
</span>
|
1452 |
-
<span class="counter-count"><?php echo number_format_i18n( $ratecount ); ?></span>
|
1453 |
-
</div>
|
1454 |
-
<?php
|
1455 |
-
}
|
1456 |
-
}
|
1457 |
-
if ( ! empty( $api->contributors ) ) {
|
1458 |
-
?>
|
1459 |
-
<h3><?php fs_echo_inline( 'Contributors', 'contributors', $api->slug ); ?></h3>
|
1460 |
-
<ul class="contributors">
|
1461 |
-
<?php
|
1462 |
-
foreach ( (array) $api->contributors as $contrib_username => $contrib_profile ) {
|
1463 |
-
if ( empty( $contrib_username ) && empty( $contrib_profile ) ) {
|
1464 |
-
continue;
|
1465 |
-
}
|
1466 |
-
if ( empty( $contrib_username ) ) {
|
1467 |
-
$contrib_username = preg_replace( '/^.+\/(.+)\/?$/', '\1', $contrib_profile );
|
1468 |
-
}
|
1469 |
-
$contrib_username = sanitize_user( $contrib_username );
|
1470 |
-
if ( empty( $contrib_profile ) ) {
|
1471 |
-
echo "<li><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&s=36' width='18' height='18' />{$contrib_username}</li>";
|
1472 |
-
} else {
|
1473 |
-
echo "<li><a href='{$contrib_profile}' target='_blank' rel='noopener noreferrer'><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&s=36' width='18' height='18' />{$contrib_username}</a></li>";
|
1474 |
-
}
|
1475 |
-
}
|
1476 |
-
?>
|
1477 |
-
</ul>
|
1478 |
-
<?php if ( ! empty( $api->donate_link ) ) { ?>
|
1479 |
-
<a target="_blank"
|
1480 |
-
rel="noopener noreferrer"
|
1481 |
-
href="<?php echo esc_url( $api->donate_link ); ?>"><?php fs_echo_inline( 'Donate to this plugin', 'donate-to-plugin', $api->slug ) ?>
|
1482 |
-
»</a>
|
1483 |
-
<?php } ?>
|
1484 |
-
<?php } ?>
|
1485 |
-
</div>
|
1486 |
-
<div id="section-holder" class="wrap">
|
1487 |
-
<?php
|
1488 |
-
if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
|
1489 |
-
echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text_inline( 'Warning', 'warning', $api->slug ) . ':</strong> ' . fs_text_inline( 'This plugin has not been tested with your current version of WordPress.', 'not-tested-warning', $api->slug ) . '</p></div>';
|
1490 |
-
} else if ( ! empty( $api->requires ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->requires ) ), $api->requires, '<' ) ) {
|
1491 |
-
echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text_inline( 'Warning', 'warning', $api->slug ) . ':</strong> ' . fs_text_inline( 'This plugin has not been marked as compatible with your version of WordPress.', 'not-compatible-warning', $api->slug ) . '</p></div>';
|
1492 |
-
}
|
1493 |
-
|
1494 |
-
foreach ( (array) $api->sections as $section_name => $content ) {
|
1495 |
-
$content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' );
|
1496 |
-
$content = links_add_target( $content, '_blank' );
|
1497 |
-
|
1498 |
-
$san_section = esc_attr( $section_name );
|
1499 |
-
|
1500 |
-
$display = ( $section_name === $section ) ? 'block' : 'none';
|
1501 |
-
|
1502 |
-
if ( 'description' === $section_name &&
|
1503 |
-
( ( $api->is_wp_org_compliant && $api->wp_org_missing ) ||
|
1504 |
-
( ! $api->is_wp_org_compliant && $api->fs_missing ) )
|
1505 |
-
) {
|
1506 |
-
$missing_notice = array(
|
1507 |
-
'type' => 'error',
|
1508 |
-
'id' => md5( microtime() ),
|
1509 |
-
'message' => $api->is_paid ?
|
1510 |
-
fs_text_inline( 'Paid add-on must be deployed to Freemius.', 'paid-addon-not-deployed', $api->slug ) :
|
1511 |
-
fs_text_inline( 'Add-on must be deployed to WordPress.org or Freemius.', 'free-addon-not-deployed', $api->slug ),
|
1512 |
-
);
|
1513 |
-
fs_require_template( 'admin-notice.php', $missing_notice );
|
1514 |
-
}
|
1515 |
-
echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
|
1516 |
-
echo $content;
|
1517 |
-
echo "\t</div>\n";
|
1518 |
-
}
|
1519 |
-
echo "</div>\n";
|
1520 |
-
echo "</div>\n";
|
1521 |
-
echo "</div>\n"; // #plugin-information-scrollable
|
1522 |
-
echo "<div id='$tab-footer'>\n";
|
1523 |
-
|
1524 |
-
if (
|
1525 |
-
! empty( $api->download_link ) &&
|
1526 |
-
! empty( $this->status ) &&
|
1527 |
-
in_array( $this->status['status'], array( 'newer_installed', 'latest_installed' ) )
|
1528 |
-
) {
|
1529 |
-
if ( 'newer_installed' === $this->status['status'] ) {
|
1530 |
-
echo $this->get_cta(
|
1531 |
-
( $this->status['is_premium_installed'] ?
|
1532 |
-
esc_html( sprintf( fs_text_inline( 'Newer Version (%s) Installed', 'newer-installed', $api->slug ), $this->status['version'] ) ) :
|
1533 |
-
esc_html( sprintf( fs_text_inline( 'Newer Free Version (%s) Installed', 'newer-free-installed', $api->slug ), $this->status['version'] ) ) ),
|
1534 |
-
false,
|
1535 |
-
true
|
1536 |
-
);
|
1537 |
-
} else {
|
1538 |
-
echo $this->get_cta(
|
1539 |
-
( $this->status['is_premium_installed'] ?
|
1540 |
-
fs_esc_html_inline( 'Latest Version Installed', 'latest-installed', $api->slug ) :
|
1541 |
-
fs_esc_html_inline( 'Latest Free Version Installed', 'latest-free-installed', $api->slug ) ),
|
1542 |
-
false,
|
1543 |
-
true
|
1544 |
-
);
|
1545 |
-
}
|
1546 |
-
}
|
1547 |
-
|
1548 |
-
echo $this->get_actions_dropdown( $api, null );
|
1549 |
-
|
1550 |
-
echo "</div>\n";
|
1551 |
-
?>
|
1552 |
-
<script type="text/javascript">
|
1553 |
-
( function( $, undef ) {
|
1554 |
-
var $dropdowns = $( '.fs-dropdown' );
|
1555 |
-
|
1556 |
-
$( '#plugin-information' )
|
1557 |
-
.click( function( evt ) {
|
1558 |
-
var $target = $( evt.target );
|
1559 |
-
|
1560 |
-
if (
|
1561 |
-
$target.hasClass( 'fs-dropdown-arrow-button' ) ||
|
1562 |
-
( 0 !== $target.parents( '.fs-dropdown-arrow-button' ).length )
|
1563 |
-
) {
|
1564 |
-
var $dropdown = $target.parents( '.fs-dropdown' ),
|
1565 |
-
isActive = $dropdown.hasClass( 'active' );
|
1566 |
-
|
1567 |
-
if ( ! isActive ) {
|
1568 |
-
/**
|
1569 |
-
* Close the other dropdown if it's active.
|
1570 |
-
*
|
1571 |
-
* @author Leo Fajardo (@leorw)
|
1572 |
-
* @since 2.3.0
|
1573 |
-
*/
|
1574 |
-
$( '.fs-dropdown.active' ).each( function() {
|
1575 |
-
toggleDropdown( $( this ), false );
|
1576 |
-
} );
|
1577 |
-
}
|
1578 |
-
|
1579 |
-
/**
|
1580 |
-
* Toggle the current dropdown.
|
1581 |
-
*
|
1582 |
-
* @author Leo Fajardo (@leorw)
|
1583 |
-
* @since 2.3.0
|
1584 |
-
*/
|
1585 |
-
toggleDropdown( $dropdown, ! isActive );
|
1586 |
-
|
1587 |
-
return true;
|
1588 |
-
}
|
1589 |
-
|
1590 |
-
/**
|
1591 |
-
* Close all dropdowns.
|
1592 |
-
*
|
1593 |
-
* @author Leo Fajardo (@leorw)
|
1594 |
-
* @since 2.3.0
|
1595 |
-
*/
|
1596 |
-
toggleDropdown( $( this ).find( '.fs-dropdown' ), false );
|
1597 |
-
});
|
1598 |
-
|
1599 |
-
if ( 0 !== $dropdowns.length ) {
|
1600 |
-
/**
|
1601 |
-
* Add the `up` class so that the bottom dropdown's content will be shown above its buttons.
|
1602 |
-
*
|
1603 |
-
* @author Leo Fajardo (@leorw)
|
1604 |
-
* @since 2.3.0
|
1605 |
-
*/
|
1606 |
-
$( '#plugin-information-footer' ).find( '.fs-dropdown' ).addClass( 'up' );
|
1607 |
-
}
|
1608 |
-
|
1609 |
-
/**
|
1610 |
-
* Returns the default state of the dropdown arrow button and hides the dropdown list.
|
1611 |
-
*
|
1612 |
-
* @author Leo Fajardo (@leorw)
|
1613 |
-
* @since 2.3.0
|
1614 |
-
*
|
1615 |
-
* @param {Object} [$dropdown]
|
1616 |
-
* @param {Boolean} [state]
|
1617 |
-
*/
|
1618 |
-
function toggleDropdown( $dropdown, state ) {
|
1619 |
-
if ( undef === $dropdown ) {
|
1620 |
-
var $activeDropdown = $dropdowns.find( '.active' );
|
1621 |
-
if ( 0 !== $activeDropdown.length ) {
|
1622 |
-
$dropdown = $activeDropdown;
|
1623 |
-
}
|
1624 |
-
}
|
1625 |
-
|
1626 |
-
if ( undef === $dropdown ) {
|
1627 |
-
return;
|
1628 |
-
}
|
1629 |
-
|
1630 |
-
if ( undef === state ) {
|
1631 |
-
state = false;
|
1632 |
-
}
|
1633 |
-
|
1634 |
-
$dropdown.toggleClass( 'active', state );
|
1635 |
-
$dropdown.find( '.fs-dropdown-list' ).toggle( state );
|
1636 |
-
$dropdown.find( '.fs-dropdown-arrow-button' ).toggleClass( 'active', state );
|
1637 |
-
}
|
1638 |
-
} )( jQuery );
|
1639 |
-
</script>
|
1640 |
-
<?php
|
1641 |
-
iframe_footer();
|
1642 |
-
exit;
|
1643 |
-
}
|
1644 |
-
}
|
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 1.0.6
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Class FS_Plugin_Info_Dialog
|
15 |
+
*
|
16 |
+
* @author Vova Feldman (@svovaf)
|
17 |
+
* @since 1.1.7
|
18 |
+
*/
|
19 |
+
class FS_Plugin_Info_Dialog {
|
20 |
+
/**
|
21 |
+
* @since 1.1.7
|
22 |
+
*
|
23 |
+
* @var FS_Logger
|
24 |
+
*/
|
25 |
+
private $_logger;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @since 1.1.7
|
29 |
+
*
|
30 |
+
* @var Freemius
|
31 |
+
*/
|
32 |
+
private $_fs;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Collection of plugin installation, update, download, activation, and purchase actions. This is used in
|
36 |
+
* populating the actions dropdown list when there are at least 2 actions. If there's only 1 action, a button
|
37 |
+
* is used instead.
|
38 |
+
*
|
39 |
+
* @author Leo Fajardo (@leorw)
|
40 |
+
* @since 2.3.0
|
41 |
+
*
|
42 |
+
* @var string[]
|
43 |
+
*/
|
44 |
+
private $actions;
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Contains plugin status information that is used to determine which actions should be part of the actions
|
48 |
+
* dropdown list.
|
49 |
+
*
|
50 |
+
* @author Leo Fajardo (@leorw)
|
51 |
+
* @since 2.3.0
|
52 |
+
*
|
53 |
+
* @var string[]
|
54 |
+
*/
|
55 |
+
private $status;
|
56 |
+
|
57 |
+
function __construct( Freemius $fs ) {
|
58 |
+
$this->_fs = $fs;
|
59 |
+
|
60 |
+
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $fs->get_slug() . '_info', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
61 |
+
|
62 |
+
// Remove default plugin information action.
|
63 |
+
remove_all_actions( 'install_plugins_pre_plugin-information' );
|
64 |
+
|
65 |
+
// Override action with custom plugins function for add-ons.
|
66 |
+
add_action( 'install_plugins_pre_plugin-information', array( &$this, 'install_plugin_information' ) );
|
67 |
+
|
68 |
+
// Override request for plugin information for Add-ons.
|
69 |
+
add_filter(
|
70 |
+
'fs_plugins_api',
|
71 |
+
array( &$this, '_get_addon_info_filter' ),
|
72 |
+
WP_FS__DEFAULT_PRIORITY, 3 );
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Generate add-on plugin information.
|
77 |
+
*
|
78 |
+
* @author Vova Feldman (@svovaf)
|
79 |
+
* @since 1.0.6
|
80 |
+
*
|
81 |
+
* @param array $data
|
82 |
+
* @param string $action
|
83 |
+
* @param object|null $args
|
84 |
+
*
|
85 |
+
* @return array|null
|
86 |
+
*/
|
87 |
+
function _get_addon_info_filter( $data, $action = '', $args = null ) {
|
88 |
+
$this->_logger->entrance();
|
89 |
+
|
90 |
+
$parent_plugin_id = fs_request_get( 'parent_plugin_id', $this->_fs->get_id() );
|
91 |
+
|
92 |
+
if ( $this->_fs->get_id() != $parent_plugin_id ||
|
93 |
+
( 'plugin_information' !== $action ) ||
|
94 |
+
! isset( $args->slug )
|
95 |
+
) {
|
96 |
+
return $data;
|
97 |
+
}
|
98 |
+
|
99 |
+
// Find add-on by slug.
|
100 |
+
$selected_addon = $this->_fs->get_addon_by_slug( $args->slug, WP_FS__DEV_MODE );
|
101 |
+
|
102 |
+
if ( false === $selected_addon ) {
|
103 |
+
return $data;
|
104 |
+
}
|
105 |
+
|
106 |
+
if ( ! isset( $selected_addon->info ) ) {
|
107 |
+
// Setup some default info.
|
108 |
+
$selected_addon->info = new stdClass();
|
109 |
+
$selected_addon->info->selling_point_0 = 'Selling Point 1';
|
110 |
+
$selected_addon->info->selling_point_1 = 'Selling Point 2';
|
111 |
+
$selected_addon->info->selling_point_2 = 'Selling Point 3';
|
112 |
+
$selected_addon->info->description = '<p>Tell your users all about your add-on</p>';
|
113 |
+
}
|
114 |
+
|
115 |
+
fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
|
116 |
+
|
117 |
+
$data = $args;
|
118 |
+
|
119 |
+
$has_free_plan = false;
|
120 |
+
$has_paid_plan = false;
|
121 |
+
|
122 |
+
// Load add-on pricing.
|
123 |
+
$has_pricing = false;
|
124 |
+
$has_features = false;
|
125 |
+
$plans = false;
|
126 |
+
|
127 |
+
$result = $this->_fs->get_api_plugin_scope()->get( $this->_fs->add_show_pending( "/addons/{$selected_addon->id}/pricing.json?type=visible" ) );
|
128 |
+
|
129 |
+
if ( ! isset( $result->error ) ) {
|
130 |
+
$plans = $result->plans;
|
131 |
+
|
132 |
+
if ( is_array( $plans ) ) {
|
133 |
+
for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
|
134 |
+
$pricing = isset( $plans[ $i ]->pricing ) ? $plans[ $i ]->pricing : null;
|
135 |
+
$features = isset( $plans[ $i ]->features ) ? $plans[ $i ]->features : null;
|
136 |
+
|
137 |
+
$plans[ $i ] = new FS_Plugin_Plan( $plans[ $i ] );
|
138 |
+
$plan = $plans[ $i ];
|
139 |
+
|
140 |
+
if ( 'free' == $plans[ $i ]->name ||
|
141 |
+
! is_array( $pricing ) ||
|
142 |
+
0 == count( $pricing )
|
143 |
+
) {
|
144 |
+
$has_free_plan = true;
|
145 |
+
}
|
146 |
+
|
147 |
+
if ( is_array( $pricing ) && 0 < count( $pricing ) ) {
|
148 |
+
$filtered_pricing = array();
|
149 |
+
|
150 |
+
foreach ( $pricing as $prices ) {
|
151 |
+
$prices = new FS_Pricing( $prices );
|
152 |
+
|
153 |
+
if ( ! $prices->is_usd() ) {
|
154 |
+
/**
|
155 |
+
* Skip non-USD pricing.
|
156 |
+
*
|
157 |
+
* @author Leo Fajardo (@leorw)
|
158 |
+
* @since 2.3.1
|
159 |
+
*/
|
160 |
+
continue;
|
161 |
+
}
|
162 |
+
|
163 |
+
if ( ( $prices->has_monthly() && $prices->monthly_price > 1.0 ) ||
|
164 |
+
( $prices->has_annual() && $prices->annual_price > 1.0 ) ||
|
165 |
+
( $prices->has_lifetime() && $prices->lifetime_price > 1.0 )
|
166 |
+
) {
|
167 |
+
$filtered_pricing[] = $prices;
|
168 |
+
}
|
169 |
+
}
|
170 |
+
|
171 |
+
if ( ! empty( $filtered_pricing ) ) {
|
172 |
+
$has_paid_plan = true;
|
173 |
+
|
174 |
+
$plan->pricing = $filtered_pricing;
|
175 |
+
|
176 |
+
$has_pricing = true;
|
177 |
+
}
|
178 |
+
}
|
179 |
+
|
180 |
+
if ( is_array( $features ) && 0 < count( $features ) ) {
|
181 |
+
$plan->features = $features;
|
182 |
+
|
183 |
+
$has_features = true;
|
184 |
+
}
|
185 |
+
}
|
186 |
+
}
|
187 |
+
}
|
188 |
+
|
189 |
+
$latest = null;
|
190 |
+
|
191 |
+
if ( ! $has_paid_plan && $selected_addon->is_wp_org_compliant ) {
|
192 |
+
$repo_data = FS_Plugin_Updater::_fetch_plugin_info_from_repository(
|
193 |
+
'plugin_information', (object) array(
|
194 |
+
'slug' => $selected_addon->slug,
|
195 |
+
'is_ssl' => is_ssl(),
|
196 |
+
'fields' => array(
|
197 |
+
'banners' => true,
|
198 |
+
'reviews' => true,
|
199 |
+
'downloaded' => false,
|
200 |
+
'active_installs' => true
|
201 |
+
)
|
202 |
+
) );
|
203 |
+
|
204 |
+
if ( ! empty( $repo_data ) ) {
|
205 |
+
$data = $repo_data;
|
206 |
+
$data->wp_org_missing = false;
|
207 |
+
} else {
|
208 |
+
// Couldn't find plugin on .org.
|
209 |
+
$selected_addon->is_wp_org_compliant = false;
|
210 |
+
|
211 |
+
// Plugin is missing, not on Freemius nor WP.org.
|
212 |
+
$data->wp_org_missing = true;
|
213 |
+
}
|
214 |
+
|
215 |
+
$data->fs_missing = ( ! $has_free_plan || $data->wp_org_missing );
|
216 |
+
} else {
|
217 |
+
$data->has_purchased_license = false;
|
218 |
+
$data->wp_org_missing = false;
|
219 |
+
|
220 |
+
$fs_addon = null;
|
221 |
+
$current_addon_version = false;
|
222 |
+
if ( $this->_fs->is_addon_activated( $selected_addon->id ) ) {
|
223 |
+
$fs_addon = $this->_fs->get_addon_instance( $selected_addon->id );
|
224 |
+
$current_addon_version = $fs_addon->get_plugin_version();
|
225 |
+
} else if ( $this->_fs->is_addon_installed( $selected_addon->id ) ) {
|
226 |
+
$addon_plugin_data = get_plugin_data(
|
227 |
+
( WP_PLUGIN_DIR . '/' . $this->_fs->get_addon_basename( $selected_addon->id ) ),
|
228 |
+
false,
|
229 |
+
false
|
230 |
+
);
|
231 |
+
|
232 |
+
if ( ! empty( $addon_plugin_data ) ) {
|
233 |
+
$current_addon_version = $addon_plugin_data['Version'];
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
// Fetch latest version from Freemius.
|
238 |
+
$latest = $this->_fs->_fetch_latest_version(
|
239 |
+
$selected_addon->id,
|
240 |
+
true,
|
241 |
+
WP_FS__TIME_24_HOURS_IN_SEC,
|
242 |
+
$current_addon_version
|
243 |
+
);
|
244 |
+
|
245 |
+
if ( $has_paid_plan ) {
|
246 |
+
$blog_id = fs_request_get( 'fs_blog_id' );
|
247 |
+
$has_valid_blog_id = is_numeric( $blog_id );
|
248 |
+
|
249 |
+
if ( $has_valid_blog_id ) {
|
250 |
+
switch_to_blog( $blog_id );
|
251 |
+
}
|
252 |
+
|
253 |
+
$data->checkout_link = $this->_fs->checkout_url(
|
254 |
+
WP_FS__PERIOD_ANNUALLY,
|
255 |
+
false,
|
256 |
+
array(),
|
257 |
+
( $has_valid_blog_id ? false : null )
|
258 |
+
);
|
259 |
+
|
260 |
+
if ( $has_valid_blog_id ) {
|
261 |
+
restore_current_blog();
|
262 |
+
}
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Check if there's a purchased license in case the add-on can only be installed/downloaded as part of a purchased bundle.
|
267 |
+
*
|
268 |
+
* @author Leo Fajardo (@leorw)
|
269 |
+
* @since 2.4.1
|
270 |
+
*/
|
271 |
+
if ( is_object( $fs_addon ) ) {
|
272 |
+
$data->has_purchased_license = $fs_addon->has_active_valid_license();
|
273 |
+
} else {
|
274 |
+
$account_addons = $this->_fs->get_account_addons();
|
275 |
+
if ( ! empty( $account_addons ) && in_array( $selected_addon->id, $account_addons ) ) {
|
276 |
+
$data->has_purchased_license = true;
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
if ( $has_free_plan || $data->has_purchased_license ) {
|
281 |
+
$data->download_link = $this->_fs->_get_latest_download_local_url( $selected_addon->id );
|
282 |
+
}
|
283 |
+
|
284 |
+
$data->fs_missing = (
|
285 |
+
false === $latest &&
|
286 |
+
(
|
287 |
+
empty( $selected_addon->premium_releases_count ) ||
|
288 |
+
! ( $selected_addon->premium_releases_count > 0 )
|
289 |
+
)
|
290 |
+
);
|
291 |
+
|
292 |
+
// Fetch as much as possible info from local files.
|
293 |
+
$plugin_local_data = $this->_fs->get_plugin_data();
|
294 |
+
$data->author = $plugin_local_data['Author'];
|
295 |
+
|
296 |
+
if ( ! empty( $selected_addon->info->banner_url ) ) {
|
297 |
+
$data->banners = array(
|
298 |
+
'low' => $selected_addon->info->banner_url,
|
299 |
+
);
|
300 |
+
}
|
301 |
+
|
302 |
+
if ( ! empty( $selected_addon->info->screenshots ) ) {
|
303 |
+
$view_vars = array(
|
304 |
+
'screenshots' => $selected_addon->info->screenshots,
|
305 |
+
'plugin' => $selected_addon,
|
306 |
+
);
|
307 |
+
$data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
|
308 |
+
}
|
309 |
+
|
310 |
+
if ( is_object( $latest ) ) {
|
311 |
+
$data->version = $latest->version;
|
312 |
+
$data->last_updated = $latest->created;
|
313 |
+
$data->requires = $latest->requires_platform_version;
|
314 |
+
$data->tested = $latest->tested_up_to_version;
|
315 |
+
} else if ( ! empty( $current_addon_version ) ) {
|
316 |
+
$data->version = $current_addon_version;
|
317 |
+
} else {
|
318 |
+
// Add dummy version.
|
319 |
+
$data->version = '1.0.0';
|
320 |
+
|
321 |
+
// Add message to developer to deploy the plugin through Freemius.
|
322 |
+
}
|
323 |
+
}
|
324 |
+
|
325 |
+
$data->name = $selected_addon->title;
|
326 |
+
$view_vars = array( 'plugin' => $selected_addon );
|
327 |
+
|
328 |
+
if ( is_object( $latest ) && isset( $latest->readme ) && is_object( $latest->readme ) ) {
|
329 |
+
$latest_version_readme_data = $latest->readme;
|
330 |
+
if ( isset( $latest_version_readme_data->sections ) ) {
|
331 |
+
$data->sections = (array) $latest_version_readme_data->sections;
|
332 |
+
} else {
|
333 |
+
$data->sections = array();
|
334 |
+
}
|
335 |
+
}
|
336 |
+
|
337 |
+
$data->sections['description'] = fs_get_template( '/plugin-info/description.php', $view_vars );
|
338 |
+
|
339 |
+
if ( $has_pricing ) {
|
340 |
+
// Add plans to data.
|
341 |
+
$data->plans = $plans;
|
342 |
+
|
343 |
+
if ( $has_features ) {
|
344 |
+
$view_vars = array(
|
345 |
+
'plans' => $plans,
|
346 |
+
'plugin' => $selected_addon,
|
347 |
+
);
|
348 |
+
$data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
|
349 |
+
}
|
350 |
+
}
|
351 |
+
|
352 |
+
$data->has_free_plan = $has_free_plan;
|
353 |
+
$data->has_paid_plan = $has_paid_plan;
|
354 |
+
$data->is_paid = $has_paid_plan;
|
355 |
+
$data->is_wp_org_compliant = $selected_addon->is_wp_org_compliant;
|
356 |
+
$data->premium_slug = $selected_addon->premium_slug;
|
357 |
+
$data->addon_id = $selected_addon->id;
|
358 |
+
|
359 |
+
if ( ! isset( $data->has_purchased_license ) ) {
|
360 |
+
$data->has_purchased_license = false;
|
361 |
+
}
|
362 |
+
|
363 |
+
return $data;
|
364 |
+
}
|
365 |
+
|
366 |
+
/**
|
367 |
+
* @author Vova Feldman (@svovaf)
|
368 |
+
* @since 1.1.7
|
369 |
+
*
|
370 |
+
* @param FS_Plugin_Plan $plan
|
371 |
+
*
|
372 |
+
* @return string
|
373 |
+
*/
|
374 |
+
private function get_billing_cycle( FS_Plugin_Plan $plan ) {
|
375 |
+
$billing_cycle = null;
|
376 |
+
|
377 |
+
if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) {
|
378 |
+
$pricing = $plan->pricing[0];
|
379 |
+
if ( isset( $pricing->annual_price ) ) {
|
380 |
+
$billing_cycle = 'annual';
|
381 |
+
} else if ( isset( $pricing->monthly_price ) ) {
|
382 |
+
$billing_cycle = 'monthly';
|
383 |
+
} else if ( isset( $pricing->lifetime_price ) ) {
|
384 |
+
$billing_cycle = 'lifetime';
|
385 |
+
}
|
386 |
+
} else {
|
387 |
+
foreach ( $plan->pricing as $pricing ) {
|
388 |
+
if ( isset( $pricing->annual_price ) ) {
|
389 |
+
$billing_cycle = 'annual';
|
390 |
+
} else if ( isset( $pricing->monthly_price ) ) {
|
391 |
+
$billing_cycle = 'monthly';
|
392 |
+
} else if ( isset( $pricing->lifetime_price ) ) {
|
393 |
+
$billing_cycle = 'lifetime';
|
394 |
+
}
|
395 |
+
|
396 |
+
if ( ! is_null( $billing_cycle ) ) {
|
397 |
+
break;
|
398 |
+
}
|
399 |
+
}
|
400 |
+
}
|
401 |
+
|
402 |
+
return $billing_cycle;
|
403 |
+
}
|
404 |
+
|
405 |
+
/**
|
406 |
+
* @author Vova Feldman (@svovaf)
|
407 |
+
* @since 2.0.0
|
408 |
+
*
|
409 |
+
* @param FS_Plugin_Plan $plan
|
410 |
+
* @param FS_Pricing $pricing
|
411 |
+
*
|
412 |
+
* @return float|null|string
|
413 |
+
*/
|
414 |
+
private function get_price_tag( FS_Plugin_Plan $plan, FS_Pricing $pricing ) {
|
415 |
+
$price_tag = '';
|
416 |
+
if ( isset( $pricing->annual_price ) ) {
|
417 |
+
$price_tag = $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
|
418 |
+
} else if ( isset( $pricing->monthly_price ) ) {
|
419 |
+
$price_tag = $pricing->monthly_price . ' / mo';
|
420 |
+
} else if ( isset( $pricing->lifetime_price ) ) {
|
421 |
+
$price_tag = $pricing->lifetime_price;
|
422 |
+
}
|
423 |
+
|
424 |
+
return '$' . $price_tag;
|
425 |
+
}
|
426 |
+
|
427 |
+
/**
|
428 |
+
* @author Leo Fajardo (@leorw)
|
429 |
+
* @since 2.3.0
|
430 |
+
*
|
431 |
+
* @param object $api
|
432 |
+
* @param FS_Plugin_Plan $plan
|
433 |
+
*
|
434 |
+
* @return string
|
435 |
+
*/
|
436 |
+
private function get_actions_dropdown( $api, $plan = null ) {
|
437 |
+
$this->actions = isset( $this->actions ) ?
|
438 |
+
$this->actions :
|
439 |
+
$this->get_plugin_actions( $api );
|
440 |
+
|
441 |
+
$actions = $this->actions;
|
442 |
+
|
443 |
+
$checkout_cta = $this->get_checkout_cta( $api, $plan );
|
444 |
+
if ( ! empty( $checkout_cta ) ) {
|
445 |
+
/**
|
446 |
+
* If there's no license yet, make the checkout button the main CTA. Otherwise, make it the last item in
|
447 |
+
* the actions dropdown.
|
448 |
+
*
|
449 |
+
* @author Leo Fajardo (@leorw)
|
450 |
+
* @since 2.3.0
|
451 |
+
*/
|
452 |
+
if ( ! $api->has_purchased_license ) {
|
453 |
+
array_unshift( $actions, $checkout_cta );
|
454 |
+
} else {
|
455 |
+
$actions[] = $checkout_cta;
|
456 |
+
}
|
457 |
+
}
|
458 |
+
|
459 |
+
if ( empty( $actions ) ) {
|
460 |
+
return '';
|
461 |
+
}
|
462 |
+
|
463 |
+
$total_actions = count( $actions );
|
464 |
+
if ( 1 === $total_actions ) {
|
465 |
+
return $actions[0];
|
466 |
+
}
|
467 |
+
|
468 |
+
ob_start();
|
469 |
+
|
470 |
+
?>
|
471 |
+
<div class="fs-cta fs-dropdown">
|
472 |
+
<div class="button-group">
|
473 |
+
<?php
|
474 |
+
// This should NOT be sanitized as the $actions are HTML buttons already.
|
475 |
+
echo $actions[0] ?>
|
476 |
+
<div class="button button-primary fs-dropdown-arrow-button">
|
477 |
+
<span class="fs-dropdown-arrow"></span>
|
478 |
+
<ul class="fs-dropdown-list" style="display: none">
|
479 |
+
<?php for ( $i = 1; $i < $total_actions; $i ++ ) : ?>
|
480 |
+
<li><?php echo str_replace( 'button button-primary', '', $actions[ $i ] ) ?></li>
|
481 |
+
<?php endfor ?>
|
482 |
+
</ul>
|
483 |
+
</div>
|
484 |
+
</div>
|
485 |
+
</div>
|
486 |
+
<?php
|
487 |
+
|
488 |
+
return ob_get_clean();
|
489 |
+
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* @author Vova Feldman (@svovaf)
|
493 |
+
* @since 1.1.7
|
494 |
+
*
|
495 |
+
* @param object $api
|
496 |
+
* @param FS_Plugin_Plan $plan
|
497 |
+
*
|
498 |
+
* @return string
|
499 |
+
*/
|
500 |
+
private function get_checkout_cta( $api, $plan = null ) {
|
501 |
+
if ( empty( $api->checkout_link ) ||
|
502 |
+
! isset( $api->plans ) ||
|
503 |
+
! is_array( $api->plans ) ||
|
504 |
+
0 == count( $api->plans )
|
505 |
+
) {
|
506 |
+
return '';
|
507 |
+
}
|
508 |
+
|
509 |
+
if ( is_null( $plan ) ) {
|
510 |
+
foreach ( $api->plans as $p ) {
|
511 |
+
if ( ! empty( $p->pricing ) ) {
|
512 |
+
$plan = $p;
|
513 |
+
break;
|
514 |
+
}
|
515 |
+
}
|
516 |
+
}
|
517 |
+
|
518 |
+
$blog_id = fs_request_get( 'fs_blog_id' );
|
519 |
+
$has_valid_blog_id = is_numeric( $blog_id );
|
520 |
+
|
521 |
+
if ( $has_valid_blog_id ) {
|
522 |
+
switch_to_blog( $blog_id );
|
523 |
+
}
|
524 |
+
|
525 |
+
$addon_checkout_url = $this->_fs->addon_checkout_url(
|
526 |
+
$plan->plugin_id,
|
527 |
+
$plan->pricing[0]->id,
|
528 |
+
$this->get_billing_cycle( $plan ),
|
529 |
+
$plan->has_trial(),
|
530 |
+
( $has_valid_blog_id ? false : null )
|
531 |
+
);
|
532 |
+
|
533 |
+
if ( $has_valid_blog_id ) {
|
534 |
+
restore_current_blog();
|
535 |
+
}
|
536 |
+
|
537 |
+
return '<a class="button button-primary fs-checkout-button right" href="' . $addon_checkout_url . '" target="_parent">' .
|
538 |
+
esc_html( ! $plan->has_trial() ?
|
539 |
+
(
|
540 |
+
$api->has_purchased_license ?
|
541 |
+
fs_text_inline( 'Purchase More', 'purchase-more', $api->slug ) :
|
542 |
+
fs_text_x_inline( 'Purchase', 'verb', 'purchase', $api->slug )
|
543 |
+
) :
|
544 |
+
sprintf(
|
545 |
+
/* translators: %s: N-days trial */
|
546 |
+
fs_text_inline( 'Start my free %s', 'start-free-x', $api->slug ),
|
547 |
+
$this->get_trial_period( $plan )
|
548 |
+
)
|
549 |
+
) .
|
550 |
+
'</a>';
|
551 |
+
}
|
552 |
+
|
553 |
+
/**
|
554 |
+
* @author Leo Fajardo (@leorw)
|
555 |
+
* @since 2.3.0
|
556 |
+
*
|
557 |
+
* @param object $api
|
558 |
+
*
|
559 |
+
* @return string[]
|
560 |
+
*/
|
561 |
+
private function get_plugin_actions( $api ) {
|
562 |
+
$this->status = isset( $this->status ) ?
|
563 |
+
$this->status :
|
564 |
+
install_plugin_install_status( $api );
|
565 |
+
|
566 |
+
$is_update_available = ( 'update_available' === $this->status['status'] );
|
567 |
+
|
568 |
+
if ( $is_update_available && empty( $this->status['url'] ) ) {
|
569 |
+
return array();
|
570 |
+
}
|
571 |
+
|
572 |
+
$blog_id = fs_request_get( 'fs_blog_id' );
|
573 |
+
|
574 |
+
$active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $blog_id );
|
575 |
+
|
576 |
+
$actions = array();
|
577 |
+
|
578 |
+
$is_addon_activated = $this->_fs->is_addon_activated( $api->slug );
|
579 |
+
$fs_addon = null;
|
580 |
+
|
581 |
+
$is_free_installed = null;
|
582 |
+
$is_premium_installed = null;
|
583 |
+
|
584 |
+
$has_installed_version = ( 'install' !== $this->status['status'] );
|
585 |
+
|
586 |
+
if ( ! $api->has_paid_plan && ! $api->has_purchased_license ) {
|
587 |
+
/**
|
588 |
+
* Free-only add-on.
|
589 |
+
*
|
590 |
+
* @author Leo Fajardo (@leorw)
|
591 |
+
* @since 2.3.0
|
592 |
+
*/
|
593 |
+
$is_free_installed = $has_installed_version;
|
594 |
+
$is_premium_installed = false;
|
595 |
+
} else if ( ! $api->has_free_plan ) {
|
596 |
+
/**
|
597 |
+
* Premium-only add-on.
|
598 |
+
*
|
599 |
+
* @author Leo Fajardo (@leorw)
|
600 |
+
* @since 2.3.0
|
601 |
+
*/
|
602 |
+
$is_free_installed = false;
|
603 |
+
$is_premium_installed = $has_installed_version;
|
604 |
+
} else {
|
605 |
+
/**
|
606 |
+
* Freemium add-on.
|
607 |
+
*
|
608 |
+
* @author Leo Fajardo (@leorw)
|
609 |
+
* @since 2.3.0
|
610 |
+
*/
|
611 |
+
if ( ! $has_installed_version ) {
|
612 |
+
$is_free_installed = false;
|
613 |
+
$is_premium_installed = false;
|
614 |
+
} else {
|
615 |
+
$fs_addon = $is_addon_activated ?
|
616 |
+
$this->_fs->get_addon_instance( $api->slug ) :
|
617 |
+
null;
|
618 |
+
|
619 |
+
if ( is_object( $fs_addon ) ) {
|
620 |
+
if ( $fs_addon->is_premium() ) {
|
621 |
+
$is_premium_installed = true;
|
622 |
+
} else {
|
623 |
+
$is_free_installed = true;
|
624 |
+
}
|
625 |
+
}
|
626 |
+
|
627 |
+
if ( is_null( $is_free_installed ) ) {
|
628 |
+
$is_free_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . "/{$api->slug}/{$api->slug}.php" ) );
|
629 |
+
if ( ! $is_free_installed ) {
|
630 |
+
/**
|
631 |
+
* Check if there's a plugin installed in a directory named `$api->slug`.
|
632 |
+
*
|
633 |
+
* @author Leo Fajardo (@leorw)
|
634 |
+
* @since 2.3.0
|
635 |
+
*/
|
636 |
+
$installed_plugins = get_plugins( '/' . $api->slug );
|
637 |
+
$is_free_installed = ( ! empty( $installed_plugins ) );
|
638 |
+
}
|
639 |
+
}
|
640 |
+
|
641 |
+
if ( is_null( $is_premium_installed ) ) {
|
642 |
+
$is_premium_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . "/{$api->premium_slug}/{$api->slug}.php" ) );
|
643 |
+
if ( ! $is_premium_installed ) {
|
644 |
+
/**
|
645 |
+
* Check if there's a plugin installed in a directory named `$api->premium_slug`.
|
646 |
+
*
|
647 |
+
* @author Leo Fajardo (@leorw)
|
648 |
+
* @since 2.3.0
|
649 |
+
*/
|
650 |
+
$installed_plugins = get_plugins( '/' . $api->premium_slug );
|
651 |
+
$is_premium_installed = ( ! empty( $installed_plugins ) );
|
652 |
+
}
|
653 |
+
}
|
654 |
+
}
|
655 |
+
|
656 |
+
$has_installed_version = ( $is_free_installed || $is_premium_installed );
|
657 |
+
}
|
658 |
+
|
659 |
+
$this->status['is_free_installed'] = $is_free_installed;
|
660 |
+
$this->status['is_premium_installed'] = $is_premium_installed;
|
661 |
+
|
662 |
+
$can_install_free_version = false;
|
663 |
+
$can_install_free_version_update = false;
|
664 |
+
$can_download_free_version = false;
|
665 |
+
$can_activate_free_version = false;
|
666 |
+
$can_install_premium_version = false;
|
667 |
+
$can_install_premium_version_update = false;
|
668 |
+
$can_download_premium_version = false;
|
669 |
+
$can_activate_premium_version = false;
|
670 |
+
|
671 |
+
if ( ! $api->has_purchased_license ) {
|
672 |
+
if ( $api->has_free_plan ) {
|
673 |
+
if ( $has_installed_version ) {
|
674 |
+
if ( $is_update_available ) {
|
675 |
+
$can_install_free_version_update = true;
|
676 |
+
} else if ( ! $is_premium_installed && ! isset( $active_plugins_directories_map[ dirname( $this->status['file'] ) ] ) ) {
|
677 |
+
$can_activate_free_version = true;
|
678 |
+
}
|
679 |
+
} else {
|
680 |
+
if (
|
681 |
+
$this->_fs->is_premium() ||
|
682 |
+
! $this->_fs->is_org_repo_compliant() ||
|
683 |
+
$api->is_wp_org_compliant
|
684 |
+
) {
|
685 |
+
$can_install_free_version = true;
|
686 |
+
} else {
|
687 |
+
$can_download_free_version = true;
|
688 |
+
}
|
689 |
+
}
|
690 |
+
}
|
691 |
+
} else {
|
692 |
+
if ( ! is_object( $fs_addon ) && $is_addon_activated ) {
|
693 |
+
$fs_addon = $this->_fs->get_addon_instance( $api->slug );
|
694 |
+
}
|
695 |
+
|
696 |
+
$can_download_premium_version = true;
|
697 |
+
|
698 |
+
if ( ! isset( $active_plugins_directories_map[ dirname( $this->status['file'] ) ] ) ) {
|
699 |
+
if ( $is_premium_installed ) {
|
700 |
+
$can_activate_premium_version = ( ! $is_addon_activated || ! $fs_addon->is_premium() );
|
701 |
+
} else if ( $is_free_installed ) {
|
702 |
+
$can_activate_free_version = ( ! $is_addon_activated );
|
703 |
+
}
|
704 |
+
}
|
705 |
+
|
706 |
+
if ( $this->_fs->is_premium() || ! $this->_fs->is_org_repo_compliant() ) {
|
707 |
+
if ( $is_update_available ) {
|
708 |
+
$can_install_premium_version_update = true;
|
709 |
+
} else if ( ! $is_premium_installed ) {
|
710 |
+
$can_install_premium_version = true;
|
711 |
+
}
|
712 |
+
}
|
713 |
+
}
|
714 |
+
|
715 |
+
if (
|
716 |
+
$can_install_premium_version ||
|
717 |
+
$can_install_premium_version_update
|
718 |
+
) {
|
719 |
+
if ( is_numeric( $blog_id ) ) {
|
720 |
+
/**
|
721 |
+
* Replace the network status URL with a blog admin–based status URL if the `Add-Ons` page is loaded
|
722 |
+
* from a specific blog admin page (when `fs_blog_id` is valid) in order for plugin installation/update
|
723 |
+
* to work.
|
724 |
+
*
|
725 |
+
* @author Leo Fajardo (@leorw)
|
726 |
+
* @since 2.3.0
|
727 |
+
*/
|
728 |
+
$this->status['url'] = self::get_blog_status_url( $blog_id, $this->status['url'], $this->status['status'] );
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* Add the `fs_allow_updater_and_dialog` param to the install/update URL so that the add-on can be
|
733 |
+
* installed/updated.
|
734 |
+
*
|
735 |
+
* @author Leo Fajardo (@leorw)
|
736 |
+
* @since 2.3.0
|
737 |
+
*/
|
738 |
+
$this->status['url'] = str_replace( '?', '?fs_allow_updater_and_dialog=true&', $this->status['url'] );
|
739 |
+
}
|
740 |
+
|
741 |
+
if ( $can_install_free_version_update || $can_install_premium_version_update ) {
|
742 |
+
$actions[] = $this->get_cta(
|
743 |
+
( $can_install_free_version_update ?
|
744 |
+
fs_esc_html_inline( 'Install Free Version Update Now', 'install-free-version-update-now', $api->slug ) :
|
745 |
+
fs_esc_html_inline( 'Install Update Now', 'install-update-now', $api->slug ) ),
|
746 |
+
true,
|
747 |
+
false,
|
748 |
+
$this->status['url'],
|
749 |
+
'_parent'
|
750 |
+
);
|
751 |
+
} else if ( $can_install_free_version || $can_install_premium_version ) {
|
752 |
+
$actions[] = $this->get_cta(
|
753 |
+
( $can_install_free_version ?
|
754 |
+
fs_esc_html_inline( 'Install Free Version Now', 'install-free-version-now', $api->slug ) :
|
755 |
+
fs_esc_html_inline( 'Install Now', 'install-now', $api->slug ) ),
|
756 |
+
true,
|
757 |
+
false,
|
758 |
+
$this->status['url'],
|
759 |
+
'_parent'
|
760 |
+
);
|
761 |
+
}
|
762 |
+
|
763 |
+
$download_latest_action = '';
|
764 |
+
|
765 |
+
if (
|
766 |
+
! empty( $api->download_link ) &&
|
767 |
+
( $can_download_free_version || $can_download_premium_version )
|
768 |
+
) {
|
769 |
+
$download_latest_action = $this->get_cta(
|
770 |
+
( $can_download_free_version ?
|
771 |
+
fs_esc_html_x_inline( 'Download Latest Free Version', 'as download latest version', 'download-latest-free-version', $api->slug ) :
|
772 |
+
fs_esc_html_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $api->slug ) ),
|
773 |
+
true,
|
774 |
+
false,
|
775 |
+
esc_url( $api->download_link )
|
776 |
+
);
|
777 |
+
}
|
778 |
+
|
779 |
+
if ( ! $can_activate_free_version && ! $can_activate_premium_version ) {
|
780 |
+
if ( ! empty( $download_latest_action ) ) {
|
781 |
+
$actions[] = $download_latest_action;
|
782 |
+
}
|
783 |
+
} else {
|
784 |
+
$activate_action = sprintf(
|
785 |
+
'<a class="button button-primary edit" href="%s" title="%s" target="_parent">%s</a>',
|
786 |
+
wp_nonce_url( ( is_numeric( $blog_id ) ? trailingslashit( get_admin_url( $blog_id ) ) : '' ) . 'plugins.php?action=activate&plugin=' . $this->status['file'], 'activate-plugin_' . $this->status['file'] ),
|
787 |
+
fs_esc_attr_inline( 'Activate this add-on', 'activate-this-addon', $api->slug ),
|
788 |
+
$can_activate_free_version ?
|
789 |
+
fs_text_inline( 'Activate Free Version', 'activate-free', $api->slug ) :
|
790 |
+
fs_text_inline( 'Activate', 'activate', $api->slug )
|
791 |
+
);
|
792 |
+
|
793 |
+
if ( ! $can_download_premium_version && ! empty( $download_latest_action ) ) {
|
794 |
+
$actions[] = $download_latest_action;
|
795 |
+
|
796 |
+
$download_latest_action = '';
|
797 |
+
}
|
798 |
+
|
799 |
+
if ( $can_install_premium_version || $can_install_premium_version_update ) {
|
800 |
+
if ( $can_download_premium_version && ! empty( $download_latest_action ) ) {
|
801 |
+
$actions[] = $download_latest_action;
|
802 |
+
|
803 |
+
$download_latest_action = '';
|
804 |
+
}
|
805 |
+
|
806 |
+
$actions[] = $activate_action;
|
807 |
+
} else {
|
808 |
+
array_unshift( $actions, $activate_action );
|
809 |
+
}
|
810 |
+
|
811 |
+
if ( ! empty ($download_latest_action ) ) {
|
812 |
+
$actions[] = $download_latest_action;
|
813 |
+
}
|
814 |
+
}
|
815 |
+
|
816 |
+
return $actions;
|
817 |
+
}
|
818 |
+
|
819 |
+
/**
|
820 |
+
* Rebuilds the status URL based on the admin URL.
|
821 |
+
*
|
822 |
+
* @author Leo Fajardo (@leorw)
|
823 |
+
* @since 2.3.0
|
824 |
+
*
|
825 |
+
* @param int $blog_id
|
826 |
+
* @param string $network_status_url
|
827 |
+
* @param string $status
|
828 |
+
*
|
829 |
+
* @return string
|
830 |
+
*/
|
831 |
+
private static function get_blog_status_url( $blog_id, $network_status_url, $status ) {
|
832 |
+
if ( ! in_array( $status, array( 'install', 'update_available' ) ) ) {
|
833 |
+
return $network_status_url;
|
834 |
+
}
|
835 |
+
|
836 |
+
$action = ( 'install' === $status ) ?
|
837 |
+
'install-plugin' :
|
838 |
+
'upgrade-plugin';
|
839 |
+
|
840 |
+
$query = parse_url( $network_status_url, PHP_URL_QUERY );
|
841 |
+
if ( empty( $query ) ) {
|
842 |
+
return $network_status_url;
|
843 |
+
}
|
844 |
+
|
845 |
+
parse_str( html_entity_decode( $query ), $url_params );
|
846 |
+
if ( empty( $url_params ) || ! isset( $url_params['plugin'] ) ) {
|
847 |
+
return $network_status_url;
|
848 |
+
}
|
849 |
+
|
850 |
+
$plugin = $url_params['plugin'];
|
851 |
+
|
852 |
+
return wp_nonce_url( get_admin_url( $blog_id,"update.php?action={$action}&plugin={$plugin}"), "{$action}_{$plugin}");
|
853 |
+
}
|
854 |
+
|
855 |
+
/**
|
856 |
+
* Helper method to get a CTA button HTML.
|
857 |
+
*
|
858 |
+
* @author Vova Feldman (@svovaf)
|
859 |
+
* @since 2.0.0
|
860 |
+
*
|
861 |
+
* @param string $label
|
862 |
+
* @param bool $is_primary
|
863 |
+
* @param bool $is_disabled
|
864 |
+
* @param string $href
|
865 |
+
* @param string $target
|
866 |
+
*
|
867 |
+
* @return string
|
868 |
+
*/
|
869 |
+
private function get_cta(
|
870 |
+
$label,
|
871 |
+
$is_primary = true,
|
872 |
+
$is_disabled = false,
|
873 |
+
$href = '',
|
874 |
+
$target = '_blank'
|
875 |
+
) {
|
876 |
+
$classes = array();
|
877 |
+
|
878 |
+
if ( ! $is_primary ) {
|
879 |
+
$classes[] = 'left';
|
880 |
+
} else {
|
881 |
+
$classes[] = 'button-primary';
|
882 |
+
$classes[] = 'right';
|
883 |
+
}
|
884 |
+
|
885 |
+
if ( $is_disabled ) {
|
886 |
+
$classes[] = 'disabled';
|
887 |
+
}
|
888 |
+
|
889 |
+
$rel = ( '_blank' === $target ) ? ' rel="noopener noreferrer"' : '';
|
890 |
+
|
891 |
+
return sprintf(
|
892 |
+
'<a %s class="button %s">%s</a>',
|
893 |
+
empty( $href ) ? '' : 'href="' . $href . '" target="' . $target . '"' . $rel,
|
894 |
+
implode( ' ', $classes ),
|
895 |
+
$label
|
896 |
+
);
|
897 |
+
}
|
898 |
+
|
899 |
+
/**
|
900 |
+
* @author Vova Feldman (@svovaf)
|
901 |
+
* @since 1.1.7
|
902 |
+
*
|
903 |
+
* @param FS_Plugin_Plan $plan
|
904 |
+
*
|
905 |
+
* @return string
|
906 |
+
*/
|
907 |
+
private function get_trial_period( $plan ) {
|
908 |
+
$trial_period = (int) $plan->trial_period;
|
909 |
+
|
910 |
+
switch ( $trial_period ) {
|
911 |
+
case 30:
|
912 |
+
return 'month';
|
913 |
+
case 60:
|
914 |
+
return '2 months';
|
915 |
+
default:
|
916 |
+
return "{$plan->trial_period} days";
|
917 |
+
}
|
918 |
+
}
|
919 |
+
|
920 |
+
/**
|
921 |
+
* Display plugin information in dialog box form.
|
922 |
+
*
|
923 |
+
* Based on core install_plugin_information() function.
|
924 |
+
*
|
925 |
+
* @author Vova Feldman (@svovaf)
|
926 |
+
* @since 1.0.6
|
927 |
+
*/
|
928 |
+
function install_plugin_information() {
|
929 |
+
global $tab;
|
930 |
+
|
931 |
+
if ( empty( $_REQUEST['plugin'] ) ) {
|
932 |
+
return;
|
933 |
+
}
|
934 |
+
|
935 |
+
$args = array(
|
936 |
+
'slug' => wp_unslash( $_REQUEST['plugin'] ),
|
937 |
+
'is_ssl' => is_ssl(),
|
938 |
+
'fields' => array(
|
939 |
+
'banners' => true,
|
940 |
+
'reviews' => true,
|
941 |
+
'downloaded' => false,
|
942 |
+
'active_installs' => true
|
943 |
+
)
|
944 |
+
);
|
945 |
+
|
946 |
+
if ( is_array( $args ) ) {
|
947 |
+
$args = (object) $args;
|
948 |
+
}
|
949 |
+
|
950 |
+
if ( ! isset( $args->per_page ) ) {
|
951 |
+
$args->per_page = 24;
|
952 |
+
}
|
953 |
+
|
954 |
+
if ( ! isset( $args->locale ) ) {
|
955 |
+
$args->locale = get_locale();
|
956 |
+
}
|
957 |
+
|
958 |
+
$api = apply_filters( 'fs_plugins_api', false, 'plugin_information', $args );
|
959 |
+
|
960 |
+
if ( is_wp_error( $api ) ) {
|
961 |
+
wp_die( $api );
|
962 |
+
}
|
963 |
+
|
964 |
+
$plugins_allowedtags = array(
|
965 |
+
'a' => array(
|
966 |
+
'href' => array(),
|
967 |
+
'title' => array(),
|
968 |
+
'target' => array(),
|
969 |
+
// Add image style for screenshots.
|
970 |
+
'class' => array()
|
971 |
+
),
|
972 |
+
'style' => array(),
|
973 |
+
'abbr' => array( 'title' => array() ),
|
974 |
+
'acronym' => array( 'title' => array() ),
|
975 |
+
'code' => array(),
|
976 |
+
'pre' => array(),
|
977 |
+
'em' => array(),
|
978 |
+
'strong' => array(),
|
979 |
+
'div' => array( 'class' => array() ),
|
980 |
+
'span' => array( 'class' => array() ),
|
981 |
+
'p' => array(),
|
982 |
+
'ul' => array(),
|
983 |
+
'ol' => array(),
|
984 |
+
'li' => array( 'class' => array() ),
|
985 |
+
'i' => array( 'class' => array() ),
|
986 |
+
'h1' => array(),
|
987 |
+
'h2' => array(),
|
988 |
+
'h3' => array(),
|
989 |
+
'h4' => array(),
|
990 |
+
'h5' => array(),
|
991 |
+
'h6' => array(),
|
992 |
+
'img' => array( 'src' => array(), 'class' => array(), 'alt' => array() ),
|
993 |
+
// 'table' => array(),
|
994 |
+
// 'td' => array(),
|
995 |
+
// 'tr' => array(),
|
996 |
+
// 'th' => array(),
|
997 |
+
// 'thead' => array(),
|
998 |
+
// 'tbody' => array(),
|
999 |
+
);
|
1000 |
+
|
1001 |
+
$plugins_section_titles = array(
|
1002 |
+
'description' => fs_text_x_inline( 'Description', 'Plugin installer section title', 'description', $api->slug ),
|
1003 |
+
'installation' => fs_text_x_inline( 'Installation', 'Plugin installer section title', 'installation', $api->slug ),
|
1004 |
+
'faq' => fs_text_x_inline( 'FAQ', 'Plugin installer section title', 'faq', $api->slug ),
|
1005 |
+
'screenshots' => fs_text_inline( 'Screenshots', 'screenshots', $api->slug ),
|
1006 |
+
'changelog' => fs_text_x_inline( 'Changelog', 'Plugin installer section title', 'changelog', $api->slug ),
|
1007 |
+
'reviews' => fs_text_x_inline( 'Reviews', 'Plugin installer section title', 'reviews', $api->slug ),
|
1008 |
+
'other_notes' => fs_text_x_inline( 'Other Notes', 'Plugin installer section title', 'other-notes', $api->slug ),
|
1009 |
+
);
|
1010 |
+
|
1011 |
+
// Sanitize HTML
|
1012 |
+
// foreach ( (array) $api->sections as $section_name => $content ) {
|
1013 |
+
// $api->sections[$section_name] = wp_kses( $content, $plugins_allowedtags );
|
1014 |
+
// }
|
1015 |
+
|
1016 |
+
foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
|
1017 |
+
if ( isset( $api->$key ) ) {
|
1018 |
+
$api->$key = wp_kses( $api->$key, $plugins_allowedtags );
|
1019 |
+
}
|
1020 |
+
}
|
1021 |
+
|
1022 |
+
// Add after $api->slug is ready.
|
1023 |
+
$plugins_section_titles['features'] = fs_text_x_inline( 'Features & Pricing', 'Plugin installer section title', 'features-and-pricing', $api->slug );
|
1024 |
+
|
1025 |
+
$_tab = esc_attr( $tab );
|
1026 |
+
|
1027 |
+
$section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; // Default to the Description tab, Do not translate, API returns English.
|
1028 |
+
if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) {
|
1029 |
+
$section_titles = array_keys( (array) $api->sections );
|
1030 |
+
$section = array_shift( $section_titles );
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
iframe_header( fs_text_inline( 'Plugin Install', 'plugin-install', $api->slug ) );
|
1034 |
+
|
1035 |
+
$_with_banner = '';
|
1036 |
+
|
1037 |
+
// var_dump($api->banners);
|
1038 |
+
if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) {
|
1039 |
+
$_with_banner = 'with-banner';
|
1040 |
+
$low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low'];
|
1041 |
+
$high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high'];
|
1042 |
+
?>
|
1043 |
+
<style type="text/css">
|
1044 |
+
#plugin-information-title.with-banner
|
1045 |
+
{
|
1046 |
+
background-image: url( <?php echo esc_url( $low ); ?> );
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
@media only screen and ( -webkit-min-device-pixel-ratio: 1.5 )
|
1050 |
+
{
|
1051 |
+
#plugin-information-title.with-banner
|
1052 |
+
{
|
1053 |
+
background-image: url( <?php echo esc_url( $high ); ?> );
|
1054 |
+
}
|
1055 |
+
}
|
1056 |
+
</style>
|
1057 |
+
<?php
|
1058 |
+
}
|
1059 |
+
|
1060 |
+
echo '<div id="plugin-information-scrollable">';
|
1061 |
+
echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>";
|
1062 |
+
echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n";
|
1063 |
+
|
1064 |
+
foreach ( (array) $api->sections as $section_name => $content ) {
|
1065 |
+
if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) {
|
1066 |
+
continue;
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
if ( isset( $plugins_section_titles[ $section_name ] ) ) {
|
1070 |
+
$title = $plugins_section_titles[ $section_name ];
|
1071 |
+
} else {
|
1072 |
+
$title = ucwords( str_replace( '_', ' ', $section_name ) );
|
1073 |
+
}
|
1074 |
+
|
1075 |
+
$class = ( $section_name === $section ) ? ' class="current"' : '';
|
1076 |
+
$href = add_query_arg( array( 'tab' => $tab, 'section' => $section_name ) );
|
1077 |
+
$href = esc_url( $href );
|
1078 |
+
$san_section = esc_attr( $section_name );
|
1079 |
+
echo "\t<a name='$san_section' href='$href' $class>" . esc_html( $title ) . "</a>\n";
|
1080 |
+
}
|
1081 |
+
|
1082 |
+
echo "</div>\n";
|
1083 |
+
|
1084 |
+
?>
|
1085 |
+
<div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'>
|
1086 |
+
<div class="fyi">
|
1087 |
+
<?php if ( $api->is_paid ) : ?>
|
1088 |
+
<?php if ( isset( $api->plans ) ) : ?>
|
1089 |
+
<div class="plugin-information-pricing">
|
1090 |
+
<?php foreach ( $api->plans as $plan ) : ?>
|
1091 |
+
<?php
|
1092 |
+
if ( empty( $plan->pricing ) ) {
|
1093 |
+
continue;
|
1094 |
+
}
|
1095 |
+
|
1096 |
+
/**
|
1097 |
+
* @var FS_Plugin_Plan $plan
|
1098 |
+
*/
|
1099 |
+
?>
|
1100 |
+
<?php $first_pricing = $plan->pricing[0] ?>
|
1101 |
+
<?php $is_multi_cycle = $first_pricing->is_multi_cycle() ?>
|
1102 |
+
<div class="fs-plan<?php if ( ! $is_multi_cycle ) {
|
1103 |
+
echo ' fs-single-cycle';
|
1104 |
+
} ?>" data-plan-id="<?php echo $plan->id ?>">
|
1105 |
+
<h3 data-plan="<?php echo $plan->id ?>"><?php echo esc_html( sprintf( fs_text_x_inline( '%s Plan', 'e.g. Professional Plan', 'x-plan', $api->slug ), $plan->title ) ) ?></h3>
|
1106 |
+
<?php $has_annual = $first_pricing->has_annual() ?>
|
1107 |
+
<?php $has_monthly = $first_pricing->has_monthly() ?>
|
1108 |
+
<div class="nav-tab-wrapper">
|
1109 |
+
<?php $billing_cycles = array( 'monthly', 'annual', 'lifetime' ) ?>
|
1110 |
+
<?php $i = 0;
|
1111 |
+
foreach ( $billing_cycles as $cycle ) : ?>
|
1112 |
+
<?php $prop = "{$cycle}_price";
|
1113 |
+
if ( isset( $first_pricing->{$prop} ) ) : ?>
|
1114 |
+
<?php $is_featured = ( 'annual' === $cycle && $is_multi_cycle ) ?>
|
1115 |
+
<?php
|
1116 |
+
$prices = array();
|
1117 |
+
foreach ( $plan->pricing as $pricing ) {
|
1118 |
+
if ( isset( $pricing->{$prop} ) ) {
|
1119 |
+
$prices[] = array(
|
1120 |
+
'id' => $pricing->id,
|
1121 |
+
'licenses' => $pricing->licenses,
|
1122 |
+
'price' => $pricing->{$prop}
|
1123 |
+
);
|
1124 |
+
}
|
1125 |
+
}
|
1126 |
+
?>
|
1127 |
+
<a class="nav-tab" data-billing-cycle="<?php echo $cycle ?>"
|
1128 |
+
data-pricing="<?php echo esc_attr( json_encode( $prices ) ) ?>">
|
1129 |
+
<?php if ( $is_featured ) : ?>
|
1130 |
+
<label>
|
1131 |
+
★ <?php fs_esc_html_echo_x_inline( 'Best', 'e.g. the best product', 'best', $api->slug ) ?>
|
1132 |
+
★</label>
|
1133 |
+
<?php endif ?>
|
1134 |
+
<?php
|
1135 |
+
switch ( $cycle ) {
|
1136 |
+
case 'monthly':
|
1137 |
+
fs_esc_html_echo_x_inline( 'Monthly', 'as every month', 'monthly', $api->slug );
|
1138 |
+
break;
|
1139 |
+
case 'annual':
|
1140 |
+
fs_esc_html_echo_x_inline( 'Annual', 'as once a year', 'annual', $api->slug );
|
1141 |
+
break;
|
1142 |
+
case 'lifetime':
|
1143 |
+
fs_esc_html_echo_inline( 'Lifetime', 'lifetime', $api->slug );
|
1144 |
+
break;
|
1145 |
+
}
|
1146 |
+
?>
|
1147 |
+
</a>
|
1148 |
+
<?php endif ?>
|
1149 |
+
<?php $i ++; endforeach ?>
|
1150 |
+
<?php wp_enqueue_script( 'jquery' ) ?>
|
1151 |
+
<script type="text/javascript">
|
1152 |
+
(function ($, undef) {
|
1153 |
+
var
|
1154 |
+
_formatBillingFrequency = function (cycle) {
|
1155 |
+
switch (cycle) {
|
1156 |
+
case 'monthly':
|
1157 |
+
return '<?php printf( fs_text_x_inline( 'Billed %s', 'e.g. billed monthly', 'billed-x', $api->slug ), fs_text_x_inline( 'Monthly', 'as every month', 'monthly', $api->slug ) ) ?>';
|
1158 |
+
case 'annual':
|
1159 |
+
return '<?php printf( fs_text_x_inline( 'Billed %s', 'e.g. billed monthly', 'billed-x', $api->slug ), fs_text_x_inline( 'Annually', 'as once a year', 'annually', $api->slug ) ) ?>';
|
1160 |
+
case 'lifetime':
|
1161 |
+
return '<?php printf( fs_text_x_inline( 'Billed %s', 'e.g. billed monthly', 'billed-x', $api->slug ), fs_text_x_inline( 'Once', 'as once a year', 'once', $api->slug ) ) ?>';
|
1162 |
+
}
|
1163 |
+
},
|
1164 |
+
_formatLicensesTitle = function (pricing) {
|
1165 |
+
switch (pricing.licenses) {
|
1166 |
+
case 1:
|
1167 |
+
return '<?php fs_esc_attr_echo_inline( 'Single Site License', 'license-single-site', $api->slug ) ?>';
|
1168 |
+
case null:
|
1169 |
+
return '<?php fs_esc_attr_echo_inline( 'Unlimited Licenses', 'license-unlimited', $api->slug ) ?>';
|
1170 |
+
default:
|
1171 |
+
return '<?php fs_esc_attr_echo_inline( 'Up to %s Sites', 'license-x-sites', $api->slug ) ?>'.replace('%s', pricing.licenses);
|
1172 |
+
}
|
1173 |
+
},
|
1174 |
+
_formatPrice = function (pricing, cycle, multipleLicenses) {
|
1175 |
+
if (undef === multipleLicenses)
|
1176 |
+
multipleLicenses = true;
|
1177 |
+
|
1178 |
+
var priceCycle;
|
1179 |
+
switch (cycle) {
|
1180 |
+
case 'monthly':
|
1181 |
+
priceCycle = ' / <?php fs_echo_x_inline( 'mo', 'as monthly period', 'mo', $api->slug ) ?>';
|
1182 |
+
break;
|
1183 |
+
case 'lifetime':
|
1184 |
+
priceCycle = '';
|
1185 |
+
break;
|
1186 |
+
case 'annual':
|
1187 |
+
default:
|
1188 |
+
priceCycle = ' / <?php fs_echo_x_inline( 'year', 'as annual period', 'year', $api->slug ) ?>';
|
1189 |
+
break;
|
1190 |
+
}
|
1191 |
+
|
1192 |
+
if (!multipleLicenses && 1 == pricing.licenses) {
|
1193 |
+
return '$' + pricing.price + priceCycle;
|
1194 |
+
}
|
1195 |
+
|
1196 |
+
return _formatLicensesTitle(pricing) + ' - <var class="fs-price">$' + pricing.price + priceCycle + '</var>';
|
1197 |
+
},
|
1198 |
+
_checkoutUrl = function (plan, pricing, cycle) {
|
1199 |
+
return '<?php echo esc_url_raw( remove_query_arg( 'billing_cycle', add_query_arg( array( 'plugin_id' => $plan->plugin_id ), $api->checkout_link ) ) ) ?>' +
|
1200 |
+
'&plan_id=' + plan +
|
1201 |
+
'&pricing_id=' + pricing +
|
1202 |
+
'&billing_cycle=' + cycle<?php if ( $plan->has_trial() ) {
|
1203 |
+
echo " + '&trial=true'";
|
1204 |
+
}?>;
|
1205 |
+
},
|
1206 |
+
_updateCtaUrl = function (plan, pricing, cycle) {
|
1207 |
+
$('.plugin-information-pricing .fs-checkout-button, #plugin-information-footer .fs-checkout-button').attr('href', _checkoutUrl(plan, pricing, cycle));
|
1208 |
+
};
|
1209 |
+
|
1210 |
+
$(document).ready(function () {
|
1211 |
+
var $plan = $('.plugin-information-pricing .fs-plan[data-plan-id=<?php echo $plan->id ?>]');
|
1212 |
+
$plan.find('input[type=radio]').on('click', function () {
|
1213 |
+
_updateCtaUrl(
|
1214 |
+
$plan.attr('data-plan-id'),
|
1215 |
+
$(this).val(),
|
1216 |
+
$plan.find('.nav-tab-active').attr('data-billing-cycle')
|
1217 |
+
);
|
1218 |
+
|
1219 |
+
$plan.find('.fs-trial-terms .fs-price').html(
|
1220 |
+
$(this).parents('label').find('.fs-price').html()
|
1221 |
+
);
|
1222 |
+
});
|
1223 |
+
|
1224 |
+
$plan.find('.nav-tab').click(function () {
|
1225 |
+
if ($(this).hasClass('nav-tab-active'))
|
1226 |
+
return;
|
1227 |
+
|
1228 |
+
var $this = $(this),
|
1229 |
+
billingCycle = $this.attr('data-billing-cycle'),
|
1230 |
+
pricing = JSON.parse($this.attr('data-pricing')),
|
1231 |
+
$pricesList = $this.parents('.fs-plan').find('.fs-pricing-body .fs-licenses'),
|
1232 |
+
html = '';
|
1233 |
+
|
1234 |
+
// Un-select previously selected tab.
|
1235 |
+
$plan.find('.nav-tab').removeClass('nav-tab-active');
|
1236 |
+
|
1237 |
+
// Select current tab.
|
1238 |
+
$this.addClass('nav-tab-active');
|
1239 |
+
|
1240 |
+
// Render licenses prices.
|
1241 |
+
if (1 == pricing.length) {
|
1242 |
+
html = '<li><label><?php echo fs_esc_attr_x_inline( 'Price', 'noun', 'price', $api->slug ) ?>: ' + _formatPrice(pricing[0], billingCycle, false) + '</label></li>';
|
1243 |
+
} else {
|
1244 |
+
for (var i = 0; i < pricing.length; i++) {
|
1245 |
+
html += '<li><label><input name="pricing-<?php echo $plan->id ?>" type="radio" value="' + pricing[i].id + '">' + _formatPrice(pricing[i], billingCycle) + '</label></li>';
|
1246 |
+
}
|
1247 |
+
}
|
1248 |
+
$pricesList.html(html);
|
1249 |
+
|
1250 |
+
if (1 < pricing.length) {
|
1251 |
+
// Select first license option.
|
1252 |
+
$pricesList.find('li:first input').click();
|
1253 |
+
}
|
1254 |
+
else {
|
1255 |
+
_updateCtaUrl(
|
1256 |
+
$plan.attr('data-plan-id'),
|
1257 |
+
pricing[0].id,
|
1258 |
+
billingCycle
|
1259 |
+
);
|
1260 |
+
}
|
1261 |
+
|
1262 |
+
// Update billing frequency.
|
1263 |
+
$plan.find('.fs-billing-frequency').html(_formatBillingFrequency(billingCycle));
|
1264 |
+
|
1265 |
+
if ('annual' === billingCycle) {
|
1266 |
+
$plan.find('.fs-annual-discount').show();
|
1267 |
+
} else {
|
1268 |
+
$plan.find('.fs-annual-discount').hide();
|
1269 |
+
}
|
1270 |
+
});
|
1271 |
+
|
1272 |
+
<?php if ( $has_annual ) : ?>
|
1273 |
+
// Select annual by default.
|
1274 |
+
$plan.find('.nav-tab[data-billing-cycle=annual]').click();
|
1275 |
+
<?php else : ?>
|
1276 |
+
// Select first tab.
|
1277 |
+
$plan.find('.nav-tab:first').click();
|
1278 |
+
<?php endif ?>
|
1279 |
+
});
|
1280 |
+
}(jQuery));
|
1281 |
+
</script>
|
1282 |
+
</div>
|
1283 |
+
<div class="fs-pricing-body">
|
1284 |
+
<span class="fs-billing-frequency"></span>
|
1285 |
+
<?php $annual_discount = ( $has_annual && $has_monthly ) ? $plan->pricing[0]->annual_discount_percentage() : 0 ?>
|
1286 |
+
<?php if ( $annual_discount > 0 ) : ?>
|
1287 |
+
<span
|
1288 |
+
class="fs-annual-discount"><?php printf(
|
1289 |
+
/* translators: %s: Discount (e.g. discount of $5 or 10%) */
|
1290 |
+
fs_esc_html_inline( 'Save %s', 'save-x', $api->slug ), $annual_discount . '%' ) ?></span>
|
1291 |
+
<?php endif ?>
|
1292 |
+
<ul class="fs-licenses">
|
1293 |
+
</ul>
|
1294 |
+
<?php echo $this->get_actions_dropdown( $api, $plan ) ?>
|
1295 |
+
<div style="clear:both"></div>
|
1296 |
+
<?php if ( $plan->has_trial() ) : ?>
|
1297 |
+
<?php $trial_period = $this->get_trial_period( $plan ) ?>
|
1298 |
+
<ul class="fs-trial-terms">
|
1299 |
+
<li>
|
1300 |
+
<i class="dashicons dashicons-yes"></i><?php echo esc_html( sprintf( fs_text_inline( 'No commitment for %s - cancel anytime', 'no-commitment-x', $api->slug ), $trial_period ) ) ?>
|
1301 |
+
</li>
|
1302 |
+
<li>
|
1303 |
+
<i class="dashicons dashicons-yes"></i><?php printf( esc_html( fs_text_inline( 'After your free %s, pay as little as %s', 'after-x-pay-as-little-y', $api->slug ) ), $trial_period, '<var class="fs-price">' . $this->get_price_tag( $plan, $plan->pricing[0] ) . '</var>' ) ?>
|
1304 |
+
</li>
|
1305 |
+
</ul>
|
1306 |
+
<?php endif ?>
|
1307 |
+
</div>
|
1308 |
+
</div>
|
1309 |
+
</div>
|
1310 |
+
<?php endforeach ?>
|
1311 |
+
<?php endif ?>
|
1312 |
+
<?php endif ?>
|
1313 |
+
<div>
|
1314 |
+
<h3><?php fs_echo_inline( 'Details', 'details', $api->slug ) ?></h3>
|
1315 |
+
<ul>
|
1316 |
+
<?php if ( ! empty( $api->version ) ) { ?>
|
1317 |
+
<li>
|
1318 |
+
<strong><?php fs_esc_html_echo_x_inline( 'Version', 'product version', 'version', $api->slug ); ?>
|
1319 |
+
:</strong> <?php echo $api->version; ?></li>
|
1320 |
+
<?php
|
1321 |
+
}
|
1322 |
+
if ( ! empty( $api->author ) ) {
|
1323 |
+
?>
|
1324 |
+
<li>
|
1325 |
+
<strong><?php fs_echo_x_inline( 'Author', 'as the plugin author', 'author', $api->slug ); ?>
|
1326 |
+
:</strong> <?php echo links_add_target( $api->author, '_blank' ); ?>
|
1327 |
+
</li>
|
1328 |
+
<?php
|
1329 |
+
}
|
1330 |
+
if ( ! empty( $api->last_updated ) ) {
|
1331 |
+
?>
|
1332 |
+
<li><strong><?php fs_echo_inline( 'Last Updated', 'last-updated', $api->slug ); ?>
|
1333 |
+
:</strong> <span
|
1334 |
+
title="<?php echo $api->last_updated; ?>">
|
1335 |
+
<?php echo esc_html( sprintf(
|
1336 |
+
/* translators: %s: time period (e.g. "2 hours" ago) */
|
1337 |
+
fs_text_x_inline( '%s ago', 'x-ago', $api->slug ),
|
1338 |
+
human_time_diff( strtotime( $api->last_updated ) )
|
1339 |
+
) ) ?>
|
1340 |
+
</span></li>
|
1341 |
+
<?php
|
1342 |
+
}
|
1343 |
+
if ( ! empty( $api->requires ) ) {
|
1344 |
+
?>
|
1345 |
+
<li>
|
1346 |
+
<strong><?php fs_esc_html_echo_inline( 'Requires WordPress Version', 'requires-wordpress-version', $api->slug ) ?>
|
1347 |
+
:</strong> <?php echo esc_html( sprintf( fs_text_inline( '%s or higher', 'x-or-higher', $api->slug ), $api->requires ) ) ?>
|
1348 |
+
</li>
|
1349 |
+
<?php
|
1350 |
+
}
|
1351 |
+
if ( ! empty( $api->tested ) ) {
|
1352 |
+
?>
|
1353 |
+
<li>
|
1354 |
+
<strong><?php fs_esc_html_echo_inline( 'Compatible up to', 'compatible-up-to', $api->slug ); ?>
|
1355 |
+
:</strong> <?php echo $api->tested; ?>
|
1356 |
+
</li>
|
1357 |
+
<?php
|
1358 |
+
}
|
1359 |
+
if ( ! empty( $api->downloaded ) ) {
|
1360 |
+
?>
|
1361 |
+
<li>
|
1362 |
+
<strong><?php fs_esc_html_echo_inline( 'Downloaded', 'downloaded', $api->slug ) ?>
|
1363 |
+
:</strong> <?php echo esc_html( sprintf(
|
1364 |
+
( ( 1 == $api->downloaded ) ?
|
1365 |
+
/* translators: %s: 1 or One (Number of times downloaded) */
|
1366 |
+
fs_text_inline( '%s time', 'x-time', $api->slug ) :
|
1367 |
+
/* translators: %s: Number of times downloaded */
|
1368 |
+
fs_text_inline( '%s times', 'x-times', $api->slug )
|
1369 |
+
),
|
1370 |
+
number_format_i18n( $api->downloaded )
|
1371 |
+
) ); ?>
|
1372 |
+
</li>
|
1373 |
+
<?php
|
1374 |
+
}
|
1375 |
+
if ( ! empty( $api->slug ) && true == $api->is_wp_org_compliant ) {
|
1376 |
+
?>
|
1377 |
+
<li><a target="_blank"
|
1378 |
+
rel="noopener noreferrer"
|
1379 |
+
href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php fs_esc_html_echo_inline( 'WordPress.org Plugin Page', 'wp-org-plugin-page', $api->slug ) ?>
|
1380 |
+
»</a>
|
1381 |
+
</li>
|
1382 |
+
<?php
|
1383 |
+
}
|
1384 |
+
if ( ! empty( $api->homepage ) ) {
|
1385 |
+
?>
|
1386 |
+
<li><a target="_blank"
|
1387 |
+
rel="noopener noreferrer"
|
1388 |
+
href="<?php echo esc_url( $api->homepage ); ?>"><?php fs_esc_html_echo_inline( 'Plugin Homepage', 'plugin-homepage', $api->slug ) ?>
|
1389 |
+
»</a>
|
1390 |
+
</li>
|
1391 |
+
<?php
|
1392 |
+
}
|
1393 |
+
if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) {
|
1394 |
+
?>
|
1395 |
+
<li><a target="_blank"
|
1396 |
+
rel="noopener noreferrer"
|
1397 |
+
href="<?php echo esc_url( $api->donate_link ); ?>"><?php fs_esc_html_echo_inline( 'Donate to this plugin', 'donate-to-plugin', $api->slug ) ?>
|
1398 |
+
»</a>
|
1399 |
+
</li>
|
1400 |
+
<?php } ?>
|
1401 |
+
</ul>
|
1402 |
+
</div>
|
1403 |
+
<?php if ( ! empty( $api->rating ) ) { ?>
|
1404 |
+
<h3><?php fs_echo_inline( 'Average Rating', 'average-rating', $api->slug ); ?></h3>
|
1405 |
+
<?php wp_star_rating( array(
|
1406 |
+
'rating' => $api->rating,
|
1407 |
+
'type' => 'percent',
|
1408 |
+
'number' => $api->num_ratings
|
1409 |
+
) ); ?>
|
1410 |
+
<small>(<?php echo esc_html( sprintf(
|
1411 |
+
fs_text_inline( 'based on %s', 'based-on-x', $api->slug ),
|
1412 |
+
sprintf(
|
1413 |
+
( ( 1 == $api->num_ratings ) ?
|
1414 |
+
/* translators: %s: 1 or One */
|
1415 |
+
fs_text_inline( '%s rating', 'x-rating', $api->slug ) :
|
1416 |
+
/* translators: %s: Number larger than 1 */
|
1417 |
+
fs_text_inline( '%s ratings', 'x-ratings', $api->slug )
|
1418 |
+
),
|
1419 |
+
number_format_i18n( $api->num_ratings )
|
1420 |
+
) ) ) ?>)
|
1421 |
+
</small>
|
1422 |
+
<?php
|
1423 |
+
}
|
1424 |
+
|
1425 |
+
if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) {
|
1426 |
+
foreach ( $api->ratings as $key => $ratecount ) {
|
1427 |
+
// Avoid div-by-zero.
|
1428 |
+
$_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0;
|
1429 |
+
$stars_label = sprintf(
|
1430 |
+
( ( 1 == $key ) ?
|
1431 |
+
/* translators: %s: 1 or One */
|
1432 |
+
fs_text_inline( '%s star', 'x-star', $api->slug ) :
|
1433 |
+
/* translators: %s: Number larger than 1 */
|
1434 |
+
fs_text_inline( '%s stars', 'x-stars', $api->slug )
|
1435 |
+
),
|
1436 |
+
number_format_i18n( $key )
|
1437 |
+
);
|
1438 |
+
?>
|
1439 |
+
<div class="counter-container">
|
1440 |
+
<span class="counter-label"><a
|
1441 |
+
href="https://wordpress.org/support/view/plugin-reviews/<?php echo $api->slug; ?>?filter=<?php echo $key; ?>"
|
1442 |
+
target="_blank"
|
1443 |
+
rel="noopener noreferrer"
|
1444 |
+
title="<?php echo esc_attr( sprintf(
|
1445 |
+
/* translators: %s: # of stars (e.g. 5 stars) */
|
1446 |
+
fs_text_inline( 'Click to see reviews that provided a rating of %s', 'click-to-reviews', $api->slug ),
|
1447 |
+
$stars_label
|
1448 |
+
) ) ?>"><?php echo $stars_label ?></a></span>
|
1449 |
+
<span class="counter-back">
|
1450 |
+
<span class="counter-bar" style="width: <?php echo absint(92 * $_rating); ?>px;"></span>
|
1451 |
+
</span>
|
1452 |
+
<span class="counter-count"><?php echo number_format_i18n( $ratecount ); ?></span>
|
1453 |
+
</div>
|
1454 |
+
<?php
|
1455 |
+
}
|
1456 |
+
}
|
1457 |
+
if ( ! empty( $api->contributors ) ) {
|
1458 |
+
?>
|
1459 |
+
<h3><?php fs_echo_inline( 'Contributors', 'contributors', $api->slug ); ?></h3>
|
1460 |
+
<ul class="contributors">
|
1461 |
+
<?php
|
1462 |
+
foreach ( (array) $api->contributors as $contrib_username => $contrib_profile ) {
|
1463 |
+
if ( empty( $contrib_username ) && empty( $contrib_profile ) ) {
|
1464 |
+
continue;
|
1465 |
+
}
|
1466 |
+
if ( empty( $contrib_username ) ) {
|
1467 |
+
$contrib_username = preg_replace( '/^.+\/(.+)\/?$/', '\1', $contrib_profile );
|
1468 |
+
}
|
1469 |
+
$contrib_username = sanitize_user( $contrib_username );
|
1470 |
+
if ( empty( $contrib_profile ) ) {
|
1471 |
+
echo "<li><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&s=36' width='18' height='18' />{$contrib_username}</li>";
|
1472 |
+
} else {
|
1473 |
+
echo "<li><a href='{$contrib_profile}' target='_blank' rel='noopener noreferrer'><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&s=36' width='18' height='18' />{$contrib_username}</a></li>";
|
1474 |
+
}
|
1475 |
+
}
|
1476 |
+
?>
|
1477 |
+
</ul>
|
1478 |
+
<?php if ( ! empty( $api->donate_link ) ) { ?>
|
1479 |
+
<a target="_blank"
|
1480 |
+
rel="noopener noreferrer"
|
1481 |
+
href="<?php echo esc_url( $api->donate_link ); ?>"><?php fs_echo_inline( 'Donate to this plugin', 'donate-to-plugin', $api->slug ) ?>
|
1482 |
+
»</a>
|
1483 |
+
<?php } ?>
|
1484 |
+
<?php } ?>
|
1485 |
+
</div>
|
1486 |
+
<div id="section-holder" class="wrap">
|
1487 |
+
<?php
|
1488 |
+
if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
|
1489 |
+
echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text_inline( 'Warning', 'warning', $api->slug ) . ':</strong> ' . fs_text_inline( 'This plugin has not been tested with your current version of WordPress.', 'not-tested-warning', $api->slug ) . '</p></div>';
|
1490 |
+
} else if ( ! empty( $api->requires ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->requires ) ), $api->requires, '<' ) ) {
|
1491 |
+
echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text_inline( 'Warning', 'warning', $api->slug ) . ':</strong> ' . fs_text_inline( 'This plugin has not been marked as compatible with your version of WordPress.', 'not-compatible-warning', $api->slug ) . '</p></div>';
|
1492 |
+
}
|
1493 |
+
|
1494 |
+
foreach ( (array) $api->sections as $section_name => $content ) {
|
1495 |
+
$content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' );
|
1496 |
+
$content = links_add_target( $content, '_blank' );
|
1497 |
+
|
1498 |
+
$san_section = esc_attr( $section_name );
|
1499 |
+
|
1500 |
+
$display = ( $section_name === $section ) ? 'block' : 'none';
|
1501 |
+
|
1502 |
+
if ( 'description' === $section_name &&
|
1503 |
+
( ( $api->is_wp_org_compliant && $api->wp_org_missing ) ||
|
1504 |
+
( ! $api->is_wp_org_compliant && $api->fs_missing ) )
|
1505 |
+
) {
|
1506 |
+
$missing_notice = array(
|
1507 |
+
'type' => 'error',
|
1508 |
+
'id' => md5( microtime() ),
|
1509 |
+
'message' => $api->is_paid ?
|
1510 |
+
fs_text_inline( 'Paid add-on must be deployed to Freemius.', 'paid-addon-not-deployed', $api->slug ) :
|
1511 |
+
fs_text_inline( 'Add-on must be deployed to WordPress.org or Freemius.', 'free-addon-not-deployed', $api->slug ),
|
1512 |
+
);
|
1513 |
+
fs_require_template( 'admin-notice.php', $missing_notice );
|
1514 |
+
}
|
1515 |
+
echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
|
1516 |
+
echo $content;
|
1517 |
+
echo "\t</div>\n";
|
1518 |
+
}
|
1519 |
+
echo "</div>\n";
|
1520 |
+
echo "</div>\n";
|
1521 |
+
echo "</div>\n"; // #plugin-information-scrollable
|
1522 |
+
echo "<div id='$tab-footer'>\n";
|
1523 |
+
|
1524 |
+
if (
|
1525 |
+
! empty( $api->download_link ) &&
|
1526 |
+
! empty( $this->status ) &&
|
1527 |
+
in_array( $this->status['status'], array( 'newer_installed', 'latest_installed' ) )
|
1528 |
+
) {
|
1529 |
+
if ( 'newer_installed' === $this->status['status'] ) {
|
1530 |
+
echo $this->get_cta(
|
1531 |
+
( $this->status['is_premium_installed'] ?
|
1532 |
+
esc_html( sprintf( fs_text_inline( 'Newer Version (%s) Installed', 'newer-installed', $api->slug ), $this->status['version'] ) ) :
|
1533 |
+
esc_html( sprintf( fs_text_inline( 'Newer Free Version (%s) Installed', 'newer-free-installed', $api->slug ), $this->status['version'] ) ) ),
|
1534 |
+
false,
|
1535 |
+
true
|
1536 |
+
);
|
1537 |
+
} else {
|
1538 |
+
echo $this->get_cta(
|
1539 |
+
( $this->status['is_premium_installed'] ?
|
1540 |
+
fs_esc_html_inline( 'Latest Version Installed', 'latest-installed', $api->slug ) :
|
1541 |
+
fs_esc_html_inline( 'Latest Free Version Installed', 'latest-free-installed', $api->slug ) ),
|
1542 |
+
false,
|
1543 |
+
true
|
1544 |
+
);
|
1545 |
+
}
|
1546 |
+
}
|
1547 |
+
|
1548 |
+
echo $this->get_actions_dropdown( $api, null );
|
1549 |
+
|
1550 |
+
echo "</div>\n";
|
1551 |
+
?>
|
1552 |
+
<script type="text/javascript">
|
1553 |
+
( function( $, undef ) {
|
1554 |
+
var $dropdowns = $( '.fs-dropdown' );
|
1555 |
+
|
1556 |
+
$( '#plugin-information' )
|
1557 |
+
.click( function( evt ) {
|
1558 |
+
var $target = $( evt.target );
|
1559 |
+
|
1560 |
+
if (
|
1561 |
+
$target.hasClass( 'fs-dropdown-arrow-button' ) ||
|
1562 |
+
( 0 !== $target.parents( '.fs-dropdown-arrow-button' ).length )
|
1563 |
+
) {
|
1564 |
+
var $dropdown = $target.parents( '.fs-dropdown' ),
|
1565 |
+
isActive = $dropdown.hasClass( 'active' );
|
1566 |
+
|
1567 |
+
if ( ! isActive ) {
|
1568 |
+
/**
|
1569 |
+
* Close the other dropdown if it's active.
|
1570 |
+
*
|
1571 |
+
* @author Leo Fajardo (@leorw)
|
1572 |
+
* @since 2.3.0
|
1573 |
+
*/
|
1574 |
+
$( '.fs-dropdown.active' ).each( function() {
|
1575 |
+
toggleDropdown( $( this ), false );
|
1576 |
+
} );
|
1577 |
+
}
|
1578 |
+
|
1579 |
+
/**
|
1580 |
+
* Toggle the current dropdown.
|
1581 |
+
*
|
1582 |
+
* @author Leo Fajardo (@leorw)
|
1583 |
+
* @since 2.3.0
|
1584 |
+
*/
|
1585 |
+
toggleDropdown( $dropdown, ! isActive );
|
1586 |
+
|
1587 |
+
return true;
|
1588 |
+
}
|
1589 |
+
|
1590 |
+
/**
|
1591 |
+
* Close all dropdowns.
|
1592 |
+
*
|
1593 |
+
* @author Leo Fajardo (@leorw)
|
1594 |
+
* @since 2.3.0
|
1595 |
+
*/
|
1596 |
+
toggleDropdown( $( this ).find( '.fs-dropdown' ), false );
|
1597 |
+
});
|
1598 |
+
|
1599 |
+
if ( 0 !== $dropdowns.length ) {
|
1600 |
+
/**
|
1601 |
+
* Add the `up` class so that the bottom dropdown's content will be shown above its buttons.
|
1602 |
+
*
|
1603 |
+
* @author Leo Fajardo (@leorw)
|
1604 |
+
* @since 2.3.0
|
1605 |
+
*/
|
1606 |
+
$( '#plugin-information-footer' ).find( '.fs-dropdown' ).addClass( 'up' );
|
1607 |
+
}
|
1608 |
+
|
1609 |
+
/**
|
1610 |
+
* Returns the default state of the dropdown arrow button and hides the dropdown list.
|
1611 |
+
*
|
1612 |
+
* @author Leo Fajardo (@leorw)
|
1613 |
+
* @since 2.3.0
|
1614 |
+
*
|
1615 |
+
* @param {Object} [$dropdown]
|
1616 |
+
* @param {Boolean} [state]
|
1617 |
+
*/
|
1618 |
+
function toggleDropdown( $dropdown, state ) {
|
1619 |
+
if ( undef === $dropdown ) {
|
1620 |
+
var $activeDropdown = $dropdowns.find( '.active' );
|
1621 |
+
if ( 0 !== $activeDropdown.length ) {
|
1622 |
+
$dropdown = $activeDropdown;
|
1623 |
+
}
|
1624 |
+
}
|
1625 |
+
|
1626 |
+
if ( undef === $dropdown ) {
|
1627 |
+
return;
|
1628 |
+
}
|
1629 |
+
|
1630 |
+
if ( undef === state ) {
|
1631 |
+
state = false;
|
1632 |
+
}
|
1633 |
+
|
1634 |
+
$dropdown.toggleClass( 'active', state );
|
1635 |
+
$dropdown.find( '.fs-dropdown-list' ).toggle( state );
|
1636 |
+
$dropdown.find( '.fs-dropdown-arrow-button' ).toggleClass( 'active', state );
|
1637 |
+
}
|
1638 |
+
} )( jQuery );
|
1639 |
+
</script>
|
1640 |
+
<?php
|
1641 |
+
iframe_footer();
|
1642 |
+
exit;
|
1643 |
+
}
|
1644 |
+
}
|
freemius/includes/i18n.php
CHANGED
@@ -1,605 +1,605 @@
|
|
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 1.1.4
|
7 |
-
*
|
8 |
-
* @deprecated This file is no longer in use. It's still in the project for backward compatibility.
|
9 |
-
*/
|
10 |
-
|
11 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
-
exit;
|
13 |
-
}
|
14 |
-
|
15 |
-
require_once dirname( __FILE__ ) . '/l10n.php';
|
16 |
-
|
17 |
-
/**
|
18 |
-
* All strings can now be overridden.
|
19 |
-
*
|
20 |
-
* For example, if we want to override:
|
21 |
-
* 'you-are-step-away' => 'You are just one step away - %s',
|
22 |
-
*
|
23 |
-
* We can use the filter:
|
24 |
-
* fs_override_i18n( array(
|
25 |
-
* 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
|
26 |
-
* 'skip' => __( 'Not today', '{your-text_domain}' ),
|
27 |
-
* ), '{plugin_slug}' );
|
28 |
-
*
|
29 |
-
* Or with the Freemius instance:
|
30 |
-
*
|
31 |
-
* my_freemius->override_i18n( array(
|
32 |
-
* 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
|
33 |
-
* 'skip' => __( 'Not today', '{your-text_domain}' ),
|
34 |
-
* ) );
|
35 |
-
*/
|
36 |
-
global $fs_text;
|
37 |
-
|
38 |
-
$fs_text = array(
|
39 |
-
'account' => _fs_text( 'Account' ),
|
40 |
-
'addon' => _fs_text( 'Add-On' ),
|
41 |
-
'contact-us' => _fs_text( 'Contact Us' ),
|
42 |
-
'contact-support' => _fs_text( 'Contact Support' ),
|
43 |
-
'change-ownership' => _fs_text( 'Change Ownership' ),
|
44 |
-
'support' => _fs_text( 'Support' ),
|
45 |
-
'support-forum' => _fs_text( 'Support Forum' ),
|
46 |
-
'add-ons' => _fs_text( 'Add-Ons' ),
|
47 |
-
'upgrade' => _fs_x( 'Upgrade', 'verb' ),
|
48 |
-
'awesome' => _fs_text( 'Awesome' ),
|
49 |
-
'pricing' => _fs_x( 'Pricing', 'noun' ),
|
50 |
-
'price' => _fs_x( 'Price', 'noun' ),
|
51 |
-
'unlimited-updates' => _fs_text( 'Unlimited Updates' ),
|
52 |
-
'downgrade' => _fs_x( 'Downgrade', 'verb' ),
|
53 |
-
'cancel-subscription' => _fs_x( 'Cancel Subscription', 'verb' ),
|
54 |
-
'cancel-trial' => _fs_text( 'Cancel Trial' ),
|
55 |
-
'free-trial' => _fs_text( 'Free Trial' ),
|
56 |
-
'start-free-x' => _fs_text( 'Start my free %s' ),
|
57 |
-
'no-commitment-x' => _fs_text( 'No commitment for %s - cancel anytime' ),
|
58 |
-
'after-x-pay-as-little-y' => _fs_text( 'After your free %s, pay as little as %s' ),
|
59 |
-
'details' => _fs_text( 'Details' ),
|
60 |
-
'account-details' => _fs_text( 'Account Details' ),
|
61 |
-
'delete' => _fs_x( 'Delete', 'verb' ),
|
62 |
-
'show' => _fs_x( 'Show', 'verb' ),
|
63 |
-
'hide' => _fs_x( 'Hide', 'verb' ),
|
64 |
-
'edit' => _fs_x( 'Edit', 'verb' ),
|
65 |
-
'update' => _fs_x( 'Update', 'verb' ),
|
66 |
-
'date' => _fs_text( 'Date' ),
|
67 |
-
'amount' => _fs_text( 'Amount' ),
|
68 |
-
'invoice' => _fs_text( 'Invoice' ),
|
69 |
-
'billing' => _fs_text( 'Billing' ),
|
70 |
-
'payments' => _fs_text( 'Payments' ),
|
71 |
-
'delete-account' => _fs_text( 'Delete Account' ),
|
72 |
-
'dismiss' => _fs_x( 'Dismiss', 'as close a window' ),
|
73 |
-
'plan' => _fs_x( 'Plan', 'as product pricing plan' ),
|
74 |
-
'change-plan' => _fs_text( 'Change Plan' ),
|
75 |
-
'download-x-version' => _fs_x( 'Download %s Version', 'as download professional version' ),
|
76 |
-
'download-x-version-now' => _fs_x( 'Download %s version now', 'as download professional version now' ),
|
77 |
-
'download-latest' => _fs_x( 'Download Latest', 'as download latest version' ),
|
78 |
-
'you-have-x-license' => _fs_x( 'You have a %s license.', 'E.g. you have a professional license.' ),
|
79 |
-
'new' => _fs_text( 'New' ),
|
80 |
-
'free' => _fs_text( 'Free' ),
|
81 |
-
'trial' => _fs_x( 'Trial', 'as trial plan' ),
|
82 |
-
'start-trial' => _fs_x( 'Start Trial', 'as starting a trial plan' ),
|
83 |
-
'purchase' => _fs_x( 'Purchase', 'verb' ),
|
84 |
-
'purchase-license' => _fs_text( 'Purchase License' ),
|
85 |
-
'buy' => _fs_x( 'Buy', 'verb' ),
|
86 |
-
'buy-license' => _fs_text( 'Buy License' ),
|
87 |
-
'license-single-site' => _fs_text( 'Single Site License' ),
|
88 |
-
'license-unlimited' => _fs_text( 'Unlimited Licenses' ),
|
89 |
-
'license-x-sites' => _fs_text( 'Up to %s Sites' ),
|
90 |
-
'renew-license-now' => _fs_text( '%sRenew your license now%s to access version %s security & feature updates, and support.' ),
|
91 |
-
'ask-for-upgrade-email-address' => _fs_text( "Enter the email address you've used for the upgrade below and we will resend you the license key." ),
|
92 |
-
'x-plan' => _fs_x( '%s Plan', 'e.g. Professional Plan' ),
|
93 |
-
'you-are-step-away' => _fs_text( 'You are just one step away - %s' ),
|
94 |
-
'activate-x-now' => _fs_x( 'Complete "%s" Activation Now',
|
95 |
-
'%s - plugin name. As complete "Jetpack" activation now' ),
|
96 |
-
'few-plugin-tweaks' => _fs_text( 'We made a few tweaks to the %s, %s' ),
|
97 |
-
'optin-x-now' => _fs_text( 'Opt in to make "%s" better!' ),
|
98 |
-
'error' => _fs_text( 'Error' ),
|
99 |
-
'failed-finding-main-path' => _fs_text( 'Freemius SDK couldn\'t find the plugin\'s main file. Please contact sdk@freemius.com with the current error.' ),
|
100 |
-
'learn-more' => _fs_text( 'Learn more' ),
|
101 |
-
'license_not_whitelabeled' => _fs_text( "Is this your client's site? %s if you wish to hide sensitive info like your billing address and invoices from the WP Admin."),
|
102 |
-
'license_whitelabeled' => _fs_text( 'Your %s license was flagged as white-labeled to hide sensitive information from the WP Admin (e.g. your billing address and 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.'),
|
103 |
-
|
104 |
-
#region Affiliation
|
105 |
-
'affiliation' => _fs_text( 'Affiliation' ),
|
106 |
-
'affiliate' => _fs_text( 'Affiliate' ),
|
107 |
-
'affiliate-tracking' => _fs_text( '%s tracking cookie after the first visit to maximize earnings potential.' ),
|
108 |
-
'renewals-commission' => _fs_text( 'Get commission for automated subscription renewals.' ),
|
109 |
-
'affiliate-application-accepted' => _fs_text( "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s." ),
|
110 |
-
'affiliate-application-thank-you' => _fs_text( "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." ),
|
111 |
-
'affiliate-application-rejected' => _fs_text( "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." ),
|
112 |
-
'affiliate-account-suspended' => _fs_text( 'Your affiliation account was temporarily suspended.' ),
|
113 |
-
'affiliate-account-blocked' => _fs_text( 'Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support.' ),
|
114 |
-
'become-an-ambassador' => _fs_text( 'Like the %s? Become our ambassador and earn cash ;-)' ),
|
115 |
-
'become-an-ambassador-admin-notice' => _fs_text( '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!' ),
|
116 |
-
'refer-new-customers' => _fs_text( 'Refer new customers to our %s and earn %s commission on each successful sale you refer!' ),
|
117 |
-
'program-summary' => _fs_text( 'Program Summary' ),
|
118 |
-
'commission-on-new-license-purchase' => _fs_text( '%s commission when a customer purchases a new license.' ),
|
119 |
-
'unlimited-commissions' => _fs_text( 'Unlimited commissions.' ),
|
120 |
-
'minimum-payout-amount' => _fs_text( '%s minimum payout amount.' ),
|
121 |
-
'payouts-unit-and-processing' => _fs_text( 'Payouts are in USD and processed monthly via PayPal.' ),
|
122 |
-
'commission-payment' => _fs_text( 'As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days.' ),
|
123 |
-
'become-an-affiliate' => _fs_text( 'Become an affiliate' ),
|
124 |
-
'apply-to-become-an-affiliate' => _fs_text( 'Apply to become an affiliate' ),
|
125 |
-
'full-name' => _fs_text( 'Full name' ),
|
126 |
-
'paypal-account-email-address' => _fs_text( 'PayPal account email address' ),
|
127 |
-
'promotion-methods' => _fs_text( 'Promotion methods' ),
|
128 |
-
'social-media' => _fs_text( 'Social media (Facebook, Twitter, etc.)' ),
|
129 |
-
'mobile-apps' => _fs_text( 'Mobile apps' ),
|
130 |
-
'statistics-information-field-label' => _fs_text( 'Website, email, and social media statistics (optional)' ),
|
131 |
-
'statistics-information-field-desc' => _fs_text( '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).' ),
|
132 |
-
'promotion-method-desc-field-label' => _fs_text( 'How will you promote us?' ),
|
133 |
-
'promotion-method-desc-field-desc' => _fs_text( 'Please provide details on how you intend to promote %s (please be as specific as possible).' ),
|
134 |
-
'domain-field-label' => _fs_text( 'Where are you going to promote the %s?' ),
|
135 |
-
'domain-field-desc' => _fs_text( 'Enter the domain of your website or other websites from where you plan to promote the %s.' ),
|
136 |
-
'extra-domain-fields-label' => _fs_text( 'Extra Domains' ),
|
137 |
-
'extra-domain-fields-desc' => _fs_text( 'Extra domains where you will be marketing the product from.' ),
|
138 |
-
'add-another-domain' => _fs_text( 'Add another domain' ),
|
139 |
-
'remove' => _fs_x( 'Remove', 'Remove domain' ),
|
140 |
-
'email-address-is-required' => _fs_text( 'Email address is required.' ),
|
141 |
-
'domain-is-required' => _fs_text( 'Domain is required.' ),
|
142 |
-
'invalid-domain' => _fs_text( 'Invalid domain' ),
|
143 |
-
'paypal-email-address-is-required' => _fs_text( 'PayPal email address is required.' ),
|
144 |
-
'processing' => _fs_text( 'Processing...' ),
|
145 |
-
'non-expiring' => _fs_text( 'Non-expiring' ),
|
146 |
-
'account-is-pending-activation' => _fs_text( 'Account is pending activation.' ),
|
147 |
-
#endregion Affiliation
|
148 |
-
|
149 |
-
#region Account
|
150 |
-
'expiration' => _fs_x( 'Expiration', 'as expiration date' ),
|
151 |
-
'license' => _fs_x( 'License', 'as software license' ),
|
152 |
-
'not-verified' => _fs_text( 'not verified' ),
|
153 |
-
'verify-email' => _fs_text( 'Verify Email' ),
|
154 |
-
'expires-in' => _fs_x( 'Expires in %s', 'e.g. expires in 2 months' ),
|
155 |
-
'renews-in' => _fs_x( 'Auto renews in %s', 'e.g. auto renews in 2 months' ),
|
156 |
-
'no-expiration' => _fs_text( 'No expiration' ),
|
157 |
-
'expired' => _fs_text( 'Expired' ),
|
158 |
-
'cancelled' => _fs_text( 'Cancelled' ),
|
159 |
-
'in-x' => _fs_x( 'In %s', 'e.g. In 2 hours' ),
|
160 |
-
'x-ago' => _fs_x( '%s ago', 'e.g. 2 min ago' ),
|
161 |
-
/* translators: %s: Version number (e.g. 4.6 or higher) */
|
162 |
-
'x-or-higher' => _fs_text( '%s or higher' ),
|
163 |
-
'version' => _fs_x( 'Version', 'as plugin version' ),
|
164 |
-
'name' => _fs_text( 'Name' ),
|
165 |
-
'email' => _fs_text( 'Email' ),
|
166 |
-
'email-address' => _fs_text( 'Email address' ),
|
167 |
-
'verified' => _fs_text( 'Verified' ),
|
168 |
-
'module' => _fs_text( 'Module' ),
|
169 |
-
'module-type' => _fs_text( 'Module Type' ),
|
170 |
-
'plugin' => _fs_text( 'Plugin' ),
|
171 |
-
'plugins' => _fs_text( 'Plugins' ),
|
172 |
-
'theme' => _fs_text( 'Theme' ),
|
173 |
-
'themes' => _fs_text( 'Themes' ),
|
174 |
-
'path' => _fs_x( 'Path', 'as file/folder path' ),
|
175 |
-
'title' => _fs_text( 'Title' ),
|
176 |
-
'free-version' => _fs_text( 'Free version' ),
|
177 |
-
'premium-version' => _fs_text( 'Premium version' ),
|
178 |
-
'slug' => _fs_x( 'Slug', 'as WP plugin slug' ),
|
179 |
-
'id' => _fs_text( 'ID' ),
|
180 |
-
'users' => _fs_text( 'Users' ),
|
181 |
-
'module-installs' => _fs_text( '%s Installs' ),
|
182 |
-
'sites' => _fs_x( 'Sites', 'like websites' ),
|
183 |
-
'user-id' => _fs_text( 'User ID' ),
|
184 |
-
'site-id' => _fs_text( 'Site ID' ),
|
185 |
-
'public-key' => _fs_text( 'Public Key' ),
|
186 |
-
'secret-key' => _fs_text( 'Secret Key' ),
|
187 |
-
'no-secret' => _fs_x( 'No Secret', 'as secret encryption key missing' ),
|
188 |
-
'no-id' => _fs_text( 'No ID' ),
|
189 |
-
'sync-license' => _fs_x( 'Sync License', 'as synchronize license' ),
|
190 |
-
'sync' => _fs_x( 'Sync', 'as synchronize' ),
|
191 |
-
'activate-license' => _fs_text( 'Activate License' ),
|
192 |
-
'activate-free-version' => _fs_text( 'Activate Free Version' ),
|
193 |
-
'activate-license-message' => _fs_text( 'Please enter the license key that you received in the email right after the purchase:' ),
|
194 |
-
'activating-license' => _fs_text( 'Activating license...' ),
|
195 |
-
'change-license' => _fs_text( 'Change License' ),
|
196 |
-
'update-license' => _fs_text( 'Update License' ),
|
197 |
-
'deactivate-license' => _fs_text( 'Deactivate License' ),
|
198 |
-
'activate' => _fs_text( 'Activate' ),
|
199 |
-
'deactivate' => _fs_text( 'Deactivate' ),
|
200 |
-
'skip-deactivate' => _fs_text( 'Skip & Deactivate' ),
|
201 |
-
'skip-and-x' => _fs_text( 'Skip & %s' ),
|
202 |
-
'no-deactivate' => _fs_text( 'No - just deactivate' ),
|
203 |
-
'yes-do-your-thing' => _fs_text( 'Yes - do your thing' ),
|
204 |
-
'active' => _fs_x( 'Active', 'active mode' ),
|
205 |
-
'is-active' => _fs_x( 'Is Active', 'is active mode?' ),
|
206 |
-
'install-now' => _fs_text( 'Install Now' ),
|
207 |
-
'install-update-now' => _fs_text( 'Install Update Now' ),
|
208 |
-
'more-information-about-x' => _fs_text( 'More information about %s' ),
|
209 |
-
'localhost' => _fs_text( 'Localhost' ),
|
210 |
-
'activate-x-plan' => _fs_x( 'Activate %s Plan', 'as activate Professional plan' ),
|
211 |
-
'x-left' => _fs_x( '%s left', 'as 5 licenses left' ),
|
212 |
-
'last-license' => _fs_text( 'Last license' ),
|
213 |
-
'what-is-your-x' => _fs_text( 'What is your %s?' ),
|
214 |
-
'activate-this-addon' => _fs_text( 'Activate this add-on' ),
|
215 |
-
'deactivate-license-confirm' => _fs_text( 'Deactivating your license will block all premium features, but will enable you to activate the license on another site. Are you sure you want to proceed?' ),
|
216 |
-
'delete-account-x-confirm' => _fs_text( '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?' ),
|
217 |
-
'delete-account-confirm' => _fs_text( '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?' ),
|
218 |
-
'downgrade-x-confirm' => _fs_text( 'Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s.' ),
|
219 |
-
'cancel-trial-confirm' => _fs_text( 'Cancelling the trial will immediately block access to all premium features. Are you sure?' ),
|
220 |
-
'after-downgrade-non-blocking' => _fs_text( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.' ),
|
221 |
-
'after-downgrade-blocking' => _fs_text( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.' ),
|
222 |
-
'proceed-confirmation' => _fs_text( 'Are you sure you want to proceed?' ),
|
223 |
-
#endregion Account
|
224 |
-
|
225 |
-
'add-ons-for-x' => _fs_text( 'Add Ons for %s' ),
|
226 |
-
'add-ons-missing' => _fs_text( 'We could\'nt load the add-ons list. It\'s probably an issue on our side, please try to come back in few minutes.' ),
|
227 |
-
#region Plugin Deactivation
|
228 |
-
'anonymous-feedback' => _fs_text( 'Anonymous feedback' ),
|
229 |
-
'quick-feedback' => _fs_text( 'Quick feedback' ),
|
230 |
-
'deactivation-share-reason' => _fs_text( 'If you have a moment, please let us know why you are %s' ),
|
231 |
-
'deactivating' => _fs_text( 'deactivating' ),
|
232 |
-
'deactivation' => _fs_text( 'Deactivation' ),
|
233 |
-
'theme-switch' => _fs_text( 'Theme Switch' ),
|
234 |
-
'switching' => _fs_text( 'switching' ),
|
235 |
-
'switch' => _fs_text( 'Switch' ),
|
236 |
-
'activate-x' => _fs_text( 'Activate %s' ),
|
237 |
-
'deactivation-modal-button-confirm' => _fs_text( 'Yes - %s' ),
|
238 |
-
'deactivation-modal-button-submit' => _fs_text( 'Submit & %s' ),
|
239 |
-
'cancel' => _fs_text( 'Cancel' ),
|
240 |
-
'reason-no-longer-needed' => _fs_text( 'I no longer need the %s' ),
|
241 |
-
'reason-found-a-better-plugin' => _fs_text( 'I found a better %s' ),
|
242 |
-
'reason-needed-for-a-short-period' => _fs_text( 'I only needed the %s for a short period' ),
|
243 |
-
'reason-broke-my-site' => _fs_text( 'The %s broke my site' ),
|
244 |
-
'reason-suddenly-stopped-working' => _fs_text( 'The %s suddenly stopped working' ),
|
245 |
-
'reason-cant-pay-anymore' => _fs_text( "I can't pay for it anymore" ),
|
246 |
-
'reason-temporary-deactivation' => _fs_text( "It's a temporary deactivation. I'm just debugging an issue." ),
|
247 |
-
'reason-temporary-x' => _fs_text( "It's a temporary %s. I'm just debugging an issue." ),
|
248 |
-
'reason-other' => _fs_x( 'Other',
|
249 |
-
'the text of the "other" reason for deactivating the module that is shown in the modal box.' ),
|
250 |
-
'ask-for-reason-message' => _fs_text( 'Kindly tell us the reason so we can improve.' ),
|
251 |
-
'placeholder-plugin-name' => _fs_text( "What's the %s's name?" ),
|
252 |
-
'placeholder-comfortable-price' => _fs_text( 'What price would you feel comfortable paying?' ),
|
253 |
-
'reason-couldnt-make-it-work' => _fs_text( "I couldn't understand how to make it work" ),
|
254 |
-
'reason-great-but-need-specific-feature' => _fs_text( "The %s is great, but I need specific feature that you don't support" ),
|
255 |
-
'reason-not-working' => _fs_text( 'The %s is not working' ),
|
256 |
-
'reason-not-what-i-was-looking-for' => _fs_text( "It's not what I was looking for" ),
|
257 |
-
'reason-didnt-work-as-expected' => _fs_text( "The %s didn't work as expected" ),
|
258 |
-
'placeholder-feature' => _fs_text( 'What feature?' ),
|
259 |
-
'placeholder-share-what-didnt-work' => _fs_text( "Kindly share what didn't work so we can fix it for future users..." ),
|
260 |
-
'placeholder-what-youve-been-looking-for' => _fs_text( "What you've been looking for?" ),
|
261 |
-
'placeholder-what-did-you-expect' => _fs_text( "What did you expect?" ),
|
262 |
-
'reason-didnt-work' => _fs_text( "The %s didn't work" ),
|
263 |
-
'reason-dont-like-to-share-my-information' => _fs_text( "I don't like to share my information with you" ),
|
264 |
-
'dont-have-to-share-any-data' => _fs_text( "You might have missed it, but you don't have to share any data and can just %s the opt-in." ),
|
265 |
-
#endregion Plugin Deactivation
|
266 |
-
|
267 |
-
#region Connect
|
268 |
-
'hey-x' => _fs_x( 'Hey %s,', 'greeting' ),
|
269 |
-
'thanks-x' => _fs_x( 'Thanks %s!', 'a greeting. E.g. Thanks John!' ),
|
270 |
-
'connect-message' => _fs_text( 'Never miss an important update - opt in to our security and feature updates notifications, and non-sensitive diagnostic tracking with %4$s.' ),
|
271 |
-
'connect-message_on-update' => _fs_text( 'Please help us improve %1$s! If you opt in, some data about your usage of %1$s will be sent to %4$s. If you skip this, that\'s okay! %1$s will still work just fine.' ),
|
272 |
-
'pending-activation-message' => _fs_text( '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.' ),
|
273 |
-
'complete-the-install' => _fs_text( 'complete the install' ),
|
274 |
-
'start-the-trial' => _fs_text( 'start the trial' ),
|
275 |
-
'thanks-for-purchasing' => _fs_text( 'Thanks for purchasing %s! To get started, please enter your license key:' ),
|
276 |
-
'license-sync-disclaimer' => _fs_text( '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.' ),
|
277 |
-
'what-permissions' => _fs_text( 'What permissions are being granted?' ),
|
278 |
-
'permissions-profile' => _fs_text( 'Your Profile Overview' ),
|
279 |
-
'permissions-profile_desc' => _fs_text( 'Name and email address' ),
|
280 |
-
'permissions-site' => _fs_text( 'Your Site Overview' ),
|
281 |
-
'permissions-site_desc' => _fs_text( 'Site URL, WP version, PHP info, plugins & themes' ),
|
282 |
-
'permissions-events' => _fs_text( 'Current %s Events' ),
|
283 |
-
'permissions-events_desc' => _fs_text( 'Activation, deactivation and uninstall' ),
|
284 |
-
'permissions-plugins_themes' => _fs_text( 'Plugins & Themes' ),
|
285 |
-
'permissions-plugins_themes_desc' => _fs_text( 'Titles, versions and state.' ),
|
286 |
-
'permissions-admin-notices' => _fs_text( 'Admin Notices' ),
|
287 |
-
'permissions-newsletter' => _fs_text( 'Newsletter' ),
|
288 |
-
'permissions-newsletter_desc' => _fs_text( 'Updates, announcements, marketing, no spam' ),
|
289 |
-
'privacy-policy' => _fs_text( 'Privacy Policy' ),
|
290 |
-
'tos' => _fs_text( 'Terms of Service' ),
|
291 |
-
'activating' => _fs_x( 'Activating', 'as activating plugin' ),
|
292 |
-
'sending-email' => _fs_x( 'Sending email', 'as in the process of sending an email' ),
|
293 |
-
'opt-in-connect' => _fs_x( 'Allow & Continue', 'button label' ),
|
294 |
-
'agree-activate-license' => _fs_x( 'Agree & Activate License', 'button label' ),
|
295 |
-
'skip' => _fs_x( 'Skip', 'verb' ),
|
296 |
-
'click-here-to-use-plugin-anonymously' => _fs_text( 'Click here to use the plugin anonymously' ),
|
297 |
-
'resend-activation-email' => _fs_text( 'Re-send activation email' ),
|
298 |
-
'license-key' => _fs_text( 'License key' ),
|
299 |
-
'send-license-key' => _fs_text( 'Send License Key' ),
|
300 |
-
'sending-license-key' => _fs_text( 'Sending license key' ),
|
301 |
-
'have-license-key' => _fs_text( 'Have a license key?' ),
|
302 |
-
'dont-have-license-key' => _fs_text( 'Don\'t have a license key?' ),
|
303 |
-
'cant-find-license-key' => _fs_text( "Can't find your license key?" ),
|
304 |
-
'email-not-found' => _fs_text( "We couldn't find your email address in the system, are you sure it's the right address?" ),
|
305 |
-
'no-active-licenses' => _fs_text( "We can't see any active licenses associated with that email address, are you sure it's the right address?" ),
|
306 |
-
'opt-in' => _fs_text( 'Opt In' ),
|
307 |
-
'opt-out' => _fs_text( 'Opt Out' ),
|
308 |
-
'opt-out-cancel' => _fs_text( 'On second thought - I want to continue helping' ),
|
309 |
-
'opting-out' => _fs_text( 'Opting out...' ),
|
310 |
-
'opting-in' => _fs_text( 'Opting in...' ),
|
311 |
-
'opt-out-message-appreciation' => _fs_text( 'We appreciate your help in making the %s better by letting us track some usage data.' ),
|
312 |
-
'opt-out-message-usage-tracking' => _fs_text( "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." ),
|
313 |
-
'opt-out-message-clicking-opt-out' => _fs_text( 'By clicking "Opt Out", we will no longer be sending any data from %s to %s.' ),
|
314 |
-
'apply-on-all-sites-in-the-network' => _fs_text( 'Apply on all sites in the network.' ),
|
315 |
-
'delegate-to-site-admins' => _fs_text( 'Delegate to Site Admins' ),
|
316 |
-
'delegate-to-site-admins-and-continue' => _fs_text( 'Delegate to Site Admins & Continue' ),
|
317 |
-
'continue' => _fs_text( 'Continue' ),
|
318 |
-
'allow' => _fs_text( 'allow' ),
|
319 |
-
'delegate' => _fs_text( 'delegate' ),
|
320 |
-
#endregion Connect
|
321 |
-
|
322 |
-
#region Screenshots
|
323 |
-
'screenshots' => _fs_text( 'Screenshots' ),
|
324 |
-
'view-full-size-x' => _fs_text( 'Click to view full-size screenshot %d' ),
|
325 |
-
#endregion Screenshots
|
326 |
-
|
327 |
-
#region Debug
|
328 |
-
'freemius-debug' => _fs_text( 'Freemius Debug' ),
|
329 |
-
'on' => _fs_x( 'On', 'as turned on' ),
|
330 |
-
'off' => _fs_x( 'Off', 'as turned off' ),
|
331 |
-
'debugging' => _fs_x( 'Debugging', 'as code debugging' ),
|
332 |
-
'freemius-state' => _fs_text( 'Freemius State' ),
|
333 |
-
'connected' => _fs_x( 'Connected', 'as connection was successful' ),
|
334 |
-
'blocked' => _fs_x( 'Blocked', 'as connection blocked' ),
|
335 |
-
'api' => _fs_x( 'API', 'as application program interface' ),
|
336 |
-
'sdk' => _fs_x( 'SDK', 'as software development kit versions' ),
|
337 |
-
'sdk-versions' => _fs_x( 'SDK Versions', 'as software development kit versions' ),
|
338 |
-
'plugin-path' => _fs_x( 'Plugin Path', 'as plugin folder path' ),
|
339 |
-
'sdk-path' => _fs_x( 'SDK Path', 'as sdk path' ),
|
340 |
-
'addons-of-x' => _fs_text( 'Add Ons of Plugin %s' ),
|
341 |
-
'delete-all-confirm' => _fs_text( 'Are you sure you want to delete all Freemius data?' ),
|
342 |
-
'actions' => _fs_text( 'Actions' ),
|
343 |
-
'delete-all-accounts' => _fs_text( 'Delete All Accounts' ),
|
344 |
-
'start-fresh' => _fs_text( 'Start Fresh' ),
|
345 |
-
'clear-api-cache' => _fs_text( 'Clear API Cache' ),
|
346 |
-
'sync-data-from-server' => _fs_text( 'Sync Data From Server' ),
|
347 |
-
'scheduled-crons' => _fs_text( 'Scheduled Crons' ),
|
348 |
-
'cron-type' => _fs_text( 'Cron Type' ),
|
349 |
-
'plugins-themes-sync' => _fs_text( 'Plugins & Themes Sync' ),
|
350 |
-
'module-licenses' => _fs_text( '%s Licenses' ),
|
351 |
-
'debug-log' => _fs_text( 'Debug Log' ),
|
352 |
-
'all' => _fs_text( 'All' ),
|
353 |
-
'file' => _fs_text( 'File' ),
|
354 |
-
'function' => _fs_text( 'Function' ),
|
355 |
-
'process-id' => _fs_text( 'Process ID' ),
|
356 |
-
'logger' => _fs_text( 'Logger' ),
|
357 |
-
'message' => _fs_text( 'Message' ),
|
358 |
-
'download' => _fs_text( 'Download' ),
|
359 |
-
'filter' => _fs_text( 'Filter' ),
|
360 |
-
'type' => _fs_text( 'Type' ),
|
361 |
-
'all-types' => _fs_text( 'All Types' ),
|
362 |
-
'all-requests' => _fs_text( 'All Requests' ),
|
363 |
-
#endregion Debug
|
364 |
-
|
365 |
-
#region Expressions
|
366 |
-
'congrats' => _fs_x( 'Congrats', 'as congratulations' ),
|
367 |
-
'oops' => _fs_x( 'Oops', 'exclamation' ),
|
368 |
-
'yee-haw' => _fs_x( 'Yee-haw', 'interjection expressing joy or exuberance' ),
|
369 |
-
'woot' => _fs_x( 'W00t',
|
370 |
-
'(especially in electronic communication) used to express elation, enthusiasm, or triumph.' ),
|
371 |
-
'right-on' => _fs_x( 'Right on', 'a positive response' ),
|
372 |
-
'hmm' => _fs_x( 'Hmm',
|
373 |
-
'something somebody says when they are thinking about what you have just said. ' ),
|
374 |
-
'ok' => _fs_text( 'O.K' ),
|
375 |
-
'hey' => _fs_x( 'Hey', 'exclamation' ),
|
376 |
-
'heads-up' => _fs_x( 'Heads up',
|
377 |
-
'advance notice of something that will need attention.' ),
|
378 |
-
#endregion Expressions
|
379 |
-
|
380 |
-
#region Admin Notices
|
381 |
-
'you-have-latest' => _fs_text( 'Seems like you got the latest release.' ),
|
382 |
-
'you-are-good' => _fs_text( 'You are all good!' ),
|
383 |
-
'user-exist-message' => _fs_text( 'Sorry, we could not complete the email update. Another user with the same email is already registered.' ),
|
384 |
-
'user-exist-message_ownership' => _fs_text( 'If you would like to give up the ownership of the %s\'s account to %s click the Change Ownership button.' ),
|
385 |
-
'email-updated-message' => _fs_text( 'Your email was successfully updated. You should receive an email with confirmation instructions in few moments.' ),
|
386 |
-
'name-updated-message' => _fs_text( 'Your name was successfully updated.' ),
|
387 |
-
'x-updated' => _fs_text( 'You have successfully updated your %s.' ),
|
388 |
-
'name-update-failed-message' => _fs_text( 'Please provide your full name.' ),
|
389 |
-
'verification-email-sent-message' => _fs_text( 'Verification mail was just sent to %s. If you can\'t find it after 5 min, please check your spam box.' ),
|
390 |
-
'addons-info-external-message' => _fs_text( 'Just letting you know that the add-ons information of %s is being pulled from an external server.' ),
|
391 |
-
'no-cc-required' => _fs_text( 'No credit card required' ),
|
392 |
-
'premium-activated-message' => _fs_text( 'Premium %s version was successfully activated.' ),
|
393 |
-
'successful-version-upgrade-message' => _fs_text( 'The upgrade of %s was successfully completed.' ),
|
394 |
-
'activation-with-plan-x-message' => _fs_text( 'Your account was successfully activated with the %s plan.' ),
|
395 |
-
'download-latest-x-version-now' => _fs_text( 'Download the latest %s version now' ),
|
396 |
-
'follow-steps-to-complete-upgrade' => _fs_text( 'Please follow these steps to complete the upgrade' ),
|
397 |
-
'download-latest-x-version' => _fs_text( 'Download the latest %s version' ),
|
398 |
-
'download-latest-version' => _fs_text( 'Download the latest version' ),
|
399 |
-
'deactivate-free-version' => _fs_text( 'Deactivate the free version' ),
|
400 |
-
'upload-and-activate' => _fs_text( 'Upload and activate the downloaded version' ),
|
401 |
-
'howto-upload-activate' => _fs_text( 'How to upload and activate?' ),
|
402 |
-
'addon-successfully-purchased-message' => _fs_x( '%s Add-on was successfully purchased.',
|
403 |
-
'%s - product name, e.g. Facebook add-on was successfully...' ),
|
404 |
-
'addon-successfully-upgraded-message' => _fs_text( 'Your %s Add-on plan was successfully upgraded.' ),
|
405 |
-
'email-verified-message' => _fs_text( 'Your email has been successfully verified - you are AWESOME!' ),
|
406 |
-
'plan-upgraded-message' => _fs_text( 'Your plan was successfully upgraded.' ),
|
407 |
-
'plan-changed-to-x-message' => _fs_text( 'Your plan was successfully changed to %s.' ),
|
408 |
-
'license-expired-blocking-message' => _fs_text( 'Your license has expired. You can still continue using the free %s forever.' ),
|
409 |
-
'license-cancelled' => _fs_text( 'Your license has been cancelled. If you think it\'s a mistake, please contact support.' ),
|
410 |
-
'trial-started-message' => _fs_text( 'Your trial has been successfully started.' ),
|
411 |
-
'license-activated-message' => _fs_text( 'Your license was successfully activated.' ),
|
412 |
-
'no-active-license-message' => _fs_text( 'It looks like your site currently doesn\'t have an active license.' ),
|
413 |
-
'license-deactivation-message' => _fs_text( 'Your license was successfully deactivated, you are back to the %s plan.' ),
|
414 |
-
'license-deactivation-failed-message' => _fs_text( 'It looks like the license deactivation failed.' ),
|
415 |
-
'license-activation-failed-message' => _fs_text( 'It looks like the license could not be activated.' ),
|
416 |
-
'server-error-message' => _fs_text( 'Error received from the server:' ),
|
417 |
-
'trial-expired-message' => _fs_text( 'Your trial has expired. You can still continue using all our free features.' ),
|
418 |
-
'plan-x-downgraded-message' => _fs_text( 'Your plan was successfully downgraded. Your %s plan license will expire in %s.' ),
|
419 |
-
'plan-downgraded-failure-message' => _fs_text( 'Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes.' ),
|
420 |
-
'trial-cancel-no-trial-message' => _fs_text( 'It looks like you are not in trial mode anymore so there\'s nothing to cancel :)' ),
|
421 |
-
'trial-cancel-message' => _fs_text( 'Your %s free trial was successfully cancelled.' ),
|
422 |
-
'version-x-released' => _fs_x( 'Version %s was released.', '%s - numeric version number' ),
|
423 |
-
'please-download-x' => _fs_text( 'Please download %s.' ),
|
424 |
-
'latest-x-version' => _fs_x( 'the latest %s version here',
|
425 |
-
'%s - plan name, as the latest professional version here' ),
|
426 |
-
'trial-x-promotion-message' => _fs_text( 'How do you like %s so far? Test all our %s premium features with a %d-day free trial.' ),
|
427 |
-
'start-free-trial' => _fs_x( 'Start free trial', 'call to action' ),
|
428 |
-
'starting-trial' => _fs_text( 'Starting trial' ),
|
429 |
-
'please-wait' => _fs_text( 'Please wait' ),
|
430 |
-
'trial-cancel-failure-message' => _fs_text( 'Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes.' ),
|
431 |
-
'trial-utilized' => _fs_text( 'You already utilized a trial before.' ),
|
432 |
-
'in-trial-mode' => _fs_text( 'You are already running the %s in a trial mode.' ),
|
433 |
-
'trial-plan-x-not-exist' => _fs_text( 'Plan %s do not exist, therefore, can\'t start a trial.' ),
|
434 |
-
'plan-x-no-trial' => _fs_text( 'Plan %s does not support a trial period.' ),
|
435 |
-
'no-trials' => _fs_text( 'None of the %s\'s plans supports a trial period.' ),
|
436 |
-
'unexpected-api-error' => _fs_text( 'Unexpected API error. Please contact the %s\'s author with the following error.' ),
|
437 |
-
'no-commitment-for-x-days' => _fs_text( 'No commitment for %s days - cancel anytime!' ),
|
438 |
-
'license-expired-non-blocking-message' => _fs_text( '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.' ),
|
439 |
-
'could-not-activate-x' => _fs_text( 'Couldn\'t activate %s.' ),
|
440 |
-
'contact-us-with-error-message' => _fs_text( 'Please contact us with the following message:' ),
|
441 |
-
'plan-did-not-change-message' => _fs_text( '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.' ),
|
442 |
-
'contact-us-here' => _fs_text( 'Please contact us here' ),
|
443 |
-
'plan-did-not-change-email-message' => _fs_text( 'I have upgraded my account but when I try to Sync the License, the plan remains %s.' ),
|
444 |
-
#endregion Admin Notices
|
445 |
-
#region Connectivity Issues
|
446 |
-
'connectivity-test-fails-message' => _fs_text( 'From unknown reason, the API connectivity test failed.' ),
|
447 |
-
'connectivity-test-maybe-temporary' => _fs_text( 'It\'s probably a temporary issue on our end. Just to be sure, with your permission, would it be o.k to run another connectivity test?' ),
|
448 |
-
'curl-missing-message' => _fs_text( 'We use PHP cURL library for the API calls, which is a very common library and usually installed and activated out of the box. Unfortunately, cURL is not activated (or disabled) on your server.' ),
|
449 |
-
'curl-disabled-methods' => _fs_text( 'Disabled method(s):' ),
|
450 |
-
'cloudflare-blocks-connection-message' => _fs_text( 'From unknown reason, CloudFlare, the firewall we use, blocks the connection.' ),
|
451 |
-
'x-requires-access-to-api' => _fs_x( '%s requires an access to our API.',
|
452 |
-
'as pluginX requires an access to our API' ),
|
453 |
-
'squid-blocks-connection-message' => _fs_text( 'It looks like your server is using Squid ACL (access control lists), which blocks the connection.' ),
|
454 |
-
'squid-no-clue-title' => _fs_text( 'I don\'t know what is Squid or ACL, help me!' ),
|
455 |
-
'squid-no-clue-desc' => _fs_text( '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.' ),
|
456 |
-
'sysadmin-title' => _fs_text( 'I\'m a system administrator' ),
|
457 |
-
'squid-sysadmin-desc' => _fs_text( 'Great, please whitelist the following domains: %s. Once you are done, deactivate the %s and activate it again.' ),
|
458 |
-
'curl-missing-no-clue-title' => _fs_text( 'I don\'t know what is cURL or how to install it, help me!' ),
|
459 |
-
'curl-missing-no-clue-desc' => _fs_text( '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.' ),
|
460 |
-
'curl-missing-sysadmin-desc' => _fs_text( '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.' ),
|
461 |
-
'happy-to-resolve-issue-asap' => _fs_text( '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.' ),
|
462 |
-
'contact-support-before-deactivation' => _fs_text( 'Sorry for the inconvenience and we are here to help if you give us a chance.' ),
|
463 |
-
'fix-issue-title' => _fs_text( 'Yes - I\'m giving you a chance to fix it' ),
|
464 |
-
'fix-issue-desc' => _fs_text( '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.' ),
|
465 |
-
'install-previous-title' => _fs_text( 'Let\'s try your previous version' ),
|
466 |
-
'install-previous-desc' => _fs_text( 'Uninstall this version and install the previous one.' ),
|
467 |
-
'deactivate-plugin-title' => _fs_text( 'That\'s exhausting, please deactivate' ),
|
468 |
-
'deactivate-plugin-desc' => _fs_text( 'We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future.' ),
|
469 |
-
'fix-request-sent-message' => _fs_text( '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.' ),
|
470 |
-
'server-blocking-access' => _fs_x( 'Your server is blocking the access to Freemius\' API, which is crucial for %1$s synchronization. Please contact your host to whitelist %2$s',
|
471 |
-
'%1$s - plugin title, %2$s - API domain' ),
|
472 |
-
'wrong-authentication-param-message' => _fs_text( 'It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again.' ),
|
473 |
-
#endregion Connectivity Issues
|
474 |
-
#region Change Owner
|
475 |
-
'change-owner-request-sent-x' => _fs_text( '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.' ),
|
476 |
-
'change-owner-request_owner-confirmed' => _fs_text( 'Thanks for confirming the ownership change. An email was just sent to %s for final approval.' ),
|
477 |
-
'change-owner-request_candidate-confirmed' => _fs_text( '%s is the new owner of the account.' ),
|
478 |
-
#endregion Change Owner
|
479 |
-
'addon-x-cannot-run-without-y' => _fs_x( '%s cannot run without %s.',
|
480 |
-
'addonX cannot run without pluginY' ),
|
481 |
-
'addon-x-cannot-run-without-parent' => _fs_x( '%s cannot run without the plugin.', 'addonX cannot run...' ),
|
482 |
-
'plugin-x-activation-message' => _fs_x( '%s activation was successfully completed.',
|
483 |
-
'pluginX activation was successfully...' ),
|
484 |
-
'features-and-pricing' => _fs_x( 'Features & Pricing', 'Plugin installer section title' ),
|
485 |
-
'free-addon-not-deployed' => _fs_text( 'Add-on must be deployed to WordPress.org or Freemius.' ),
|
486 |
-
'paid-addon-not-deployed' => _fs_text( 'Paid add-on must be deployed to Freemius.' ),
|
487 |
-
#--------------------------------------------------------------------------------
|
488 |
-
#region Add-On Licensing
|
489 |
-
#--------------------------------------------------------------------------------
|
490 |
-
'addon-no-license-message' => _fs_text( '%s is a premium only add-on. You have to purchase a license first before activating the plugin.' ),
|
491 |
-
'addon-trial-cancelled-message' => _fs_text( '%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.' ),
|
492 |
-
#endregion
|
493 |
-
#--------------------------------------------------------------------------------
|
494 |
-
#region Billing Cycles
|
495 |
-
#--------------------------------------------------------------------------------
|
496 |
-
'monthly' => _fs_x( 'Monthly', 'as every month' ),
|
497 |
-
'mo' => _fs_x( 'mo', 'as monthly period' ),
|
498 |
-
'annual' => _fs_x( 'Annual', 'as once a year' ),
|
499 |
-
'annually' => _fs_x( 'Annually', 'as once a year' ),
|
500 |
-
'once' => _fs_x( 'Once', 'as once a year' ),
|
501 |
-
'year' => _fs_x( 'year', 'as annual period' ),
|
502 |
-
'lifetime' => _fs_text( 'Lifetime' ),
|
503 |
-
'best' => _fs_x( 'Best', 'e.g. the best product' ),
|
504 |
-
'billed-x' => _fs_x( 'Billed %s', 'e.g. billed monthly' ),
|
505 |
-
'save-x' => _fs_x( 'Save %s', 'as a discount of $5 or 10%' ),
|
506 |
-
#endregion Billing Cycles
|
507 |
-
'view-details' => _fs_text( 'View details' ),
|
508 |
-
#--------------------------------------------------------------------------------
|
509 |
-
#region Trial
|
510 |
-
#--------------------------------------------------------------------------------
|
511 |
-
'approve-start-trial' => _fs_x( 'Approve & Start Trial', 'button label' ),
|
512 |
-
/* translators: %1$s: Number of trial days; %2$s: Plan name; */
|
513 |
-
'start-trial-prompt-header' => _fs_text( 'You are 1-click away from starting your %1$s-day free trial of the %2$s plan.' ),
|
514 |
-
/* translators: %s: Link to freemius.com */
|
515 |
-
'start-trial-prompt-message' => _fs_text( 'For compliance with the WordPress.org guidelines, before we start the trial we ask that you opt in with your user and non-sensitive site information, allowing the %s to periodically send data to %s to check for version updates and to validate your trial.' ),
|
516 |
-
|
517 |
-
#endregion
|
518 |
-
#--------------------------------------------------------------------------------
|
519 |
-
#region Billing Details
|
520 |
-
#--------------------------------------------------------------------------------
|
521 |
-
'business-name' => _fs_text( 'Business name' ),
|
522 |
-
'tax-vat-id' => _fs_text( 'Tax / VAT ID' ),
|
523 |
-
'address-line-n' => _fs_text( 'Address Line %d' ),
|
524 |
-
'country' => _fs_text( 'Country' ),
|
525 |
-
'select-country' => _fs_text( 'Select Country' ),
|
526 |
-
'city' => _fs_text( 'City' ),
|
527 |
-
'town' => _fs_text( 'Town' ),
|
528 |
-
'state' => _fs_text( 'State' ),
|
529 |
-
'province' => _fs_text( 'Province' ),
|
530 |
-
'zip-postal-code' => _fs_text( 'ZIP / Postal Code' ),
|
531 |
-
#endregion
|
532 |
-
#--------------------------------------------------------------------------------
|
533 |
-
#region Module Installation
|
534 |
-
#--------------------------------------------------------------------------------
|
535 |
-
'installing-plugin-x' => _fs_text( 'Installing plugin: %s' ),
|
536 |
-
'auto-installation' => _fs_text( 'Automatic Installation' ),
|
537 |
-
/* translators: %s: Number of seconds */
|
538 |
-
'x-sec' => _fs_text( '%s sec' ),
|
539 |
-
'installing-in-n' => _fs_text( 'An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now.' ),
|
540 |
-
'installing-module-x' => _fs_text( 'The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page.' ),
|
541 |
-
'cancel-installation' => _fs_text( 'Cancel Installation' ),
|
542 |
-
'module-package-rename-failure' => _fs_text( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.' ),
|
543 |
-
'auto-install-error-invalid-id' => _fs_text( 'Invalid module ID.' ),
|
544 |
-
'auto-install-error-not-opted-in' => _fs_text( 'Auto installation only works for opted-in users.' ),
|
545 |
-
'auto-install-error-premium-activated' => _fs_text( 'Premium version already active.' ),
|
546 |
-
'auto-install-error-premium-addon-activated' => _fs_text( 'Premium add-on version already installed.' ),
|
547 |
-
'auto-install-error-invalid-license' => _fs_text( 'You do not have a valid license to access the premium version.' ),
|
548 |
-
'auto-install-error-serviceware' => _fs_text( 'Plugin is a "Serviceware" which means it does not have a premium code version.' ),
|
549 |
-
#endregion
|
550 |
-
|
551 |
-
/* translators: %s: Page name */
|
552 |
-
'secure-x-page-header' => _fs_text( 'Secure HTTPS %s page, running from an external domain' ),
|
553 |
-
'pci-compliant' => _fs_text( 'PCI compliant' ),
|
554 |
-
'view-paid-features' => _fs_text( 'View paid features' ),
|
555 |
-
);
|
556 |
-
|
557 |
-
/**
|
558 |
-
* Localization of the strings in the plugin/theme info dialog box.
|
559 |
-
*
|
560 |
-
* $fs_module_info_text should ONLY include strings that are not located in $fs_text.
|
561 |
-
*
|
562 |
-
* @author Vova Feldman (@svovaf)
|
563 |
-
* @since 1.2.2
|
564 |
-
*/
|
565 |
-
global $fs_module_info_text;
|
566 |
-
|
567 |
-
$fs_module_info_text = array(
|
568 |
-
'description' => _fs_x( 'Description', 'Plugin installer section title' ),
|
569 |
-
'installation' => _fs_x( 'Installation', 'Plugin installer section title' ),
|
570 |
-
'faq' => _fs_x( 'FAQ', 'Plugin installer section title' ),
|
571 |
-
'changelog' => _fs_x( 'Changelog', 'Plugin installer section title' ),
|
572 |
-
'reviews' => _fs_x( 'Reviews', 'Plugin installer section title' ),
|
573 |
-
'other_notes' => _fs_x( 'Other Notes', 'Plugin installer section title' ),
|
574 |
-
/* translators: %s: 1 or One */
|
575 |
-
'x-star' => _fs_text( '%s star' ),
|
576 |
-
/* translators: %s: Number larger than 1 */
|
577 |
-
'x-stars' => _fs_text( '%s stars' ),
|
578 |
-
/* translators: %s: 1 or One */
|
579 |
-
'x-rating' => _fs_text( '%s rating' ),
|
580 |
-
/* translators: %s: Number larger than 1 */
|
581 |
-
'x-ratings' => _fs_text( '%s ratings' ),
|
582 |
-
/* translators: %s: 1 or One (Number of times downloaded) */
|
583 |
-
'x-time' => _fs_text( '%s time' ),
|
584 |
-
/* translators: %s: Number of times downloaded */
|
585 |
-
'x-times' => _fs_text( '%s times' ),
|
586 |
-
/* translators: %s: # of stars (e.g. 5 stars) */
|
587 |
-
'click-to-reviews' => _fs_text( 'Click to see reviews that provided a rating of %s' ),
|
588 |
-
'last-updated:' => _fs_text( 'Last Updated' ),
|
589 |
-
'requires-wordpress-version:' => _fs_text( 'Requires WordPress Version:' ),
|
590 |
-
'author:' => _fs_x( 'Author:', 'as the plugin author' ),
|
591 |
-
'compatible-up-to:' => _fs_text( 'Compatible up to:' ),
|
592 |
-
'downloaded:' => _fs_text( 'Downloaded:' ),
|
593 |
-
'wp-org-plugin-page' => _fs_text( 'WordPress.org Plugin Page' ),
|
594 |
-
'plugin-homepage' => _fs_text( 'Plugin Homepage' ),
|
595 |
-
'donate-to-plugin' => _fs_text( 'Donate to this plugin' ),
|
596 |
-
'average-rating' => _fs_text( 'Average Rating' ),
|
597 |
-
'based-on-x' => _fs_text( 'based on %s' ),
|
598 |
-
'warning:' => _fs_text( 'Warning:' ),
|
599 |
-
'contributors' => _fs_text( 'Contributors' ),
|
600 |
-
'plugin-install' => _fs_text( 'Plugin Install' ),
|
601 |
-
'not-tested-warning' => _fs_text( 'This plugin has not been tested with your current version of WordPress.' ),
|
602 |
-
'not-compatible-warning' => _fs_text( 'This plugin has not been marked as compatible with your version of WordPress.' ),
|
603 |
-
'newer-installed' => _fs_text( 'Newer Version (%s) Installed' ),
|
604 |
-
'latest-installed' => _fs_text( 'Latest Version Installed' ),
|
605 |
-
);
|
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 1.1.4
|
7 |
+
*
|
8 |
+
* @deprecated This file is no longer in use. It's still in the project for backward compatibility.
|
9 |
+
*/
|
10 |
+
|
11 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
12 |
+
exit;
|
13 |
+
}
|
14 |
+
|
15 |
+
require_once dirname( __FILE__ ) . '/l10n.php';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* All strings can now be overridden.
|
19 |
+
*
|
20 |
+
* For example, if we want to override:
|
21 |
+
* 'you-are-step-away' => 'You are just one step away - %s',
|
22 |
+
*
|
23 |
+
* We can use the filter:
|
24 |
+
* fs_override_i18n( array(
|
25 |
+
* 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
|
26 |
+
* 'skip' => __( 'Not today', '{your-text_domain}' ),
|
27 |
+
* ), '{plugin_slug}' );
|
28 |
+
*
|
29 |
+
* Or with the Freemius instance:
|
30 |
+
*
|
31 |
+
* my_freemius->override_i18n( array(
|
32 |
+
* 'opt-in-connect' => __( "Yes - I'm in!", '{your-text_domain}' ),
|
33 |
+
* 'skip' => __( 'Not today', '{your-text_domain}' ),
|
34 |
+
* ) );
|
35 |
+
*/
|
36 |
+
global $fs_text;
|
37 |
+
|
38 |
+
$fs_text = array(
|
39 |
+
'account' => _fs_text( 'Account' ),
|
40 |
+
'addon' => _fs_text( 'Add-On' ),
|
41 |
+
'contact-us' => _fs_text( 'Contact Us' ),
|
42 |
+
'contact-support' => _fs_text( 'Contact Support' ),
|
43 |
+
'change-ownership' => _fs_text( 'Change Ownership' ),
|
44 |
+
'support' => _fs_text( 'Support' ),
|
45 |
+
'support-forum' => _fs_text( 'Support Forum' ),
|
46 |
+
'add-ons' => _fs_text( 'Add-Ons' ),
|
47 |
+
'upgrade' => _fs_x( 'Upgrade', 'verb' ),
|
48 |
+
'awesome' => _fs_text( 'Awesome' ),
|
49 |
+
'pricing' => _fs_x( 'Pricing', 'noun' ),
|
50 |
+
'price' => _fs_x( 'Price', 'noun' ),
|
51 |
+
'unlimited-updates' => _fs_text( 'Unlimited Updates' ),
|
52 |
+
'downgrade' => _fs_x( 'Downgrade', 'verb' ),
|
53 |
+
'cancel-subscription' => _fs_x( 'Cancel Subscription', 'verb' ),
|
54 |
+
'cancel-trial' => _fs_text( 'Cancel Trial' ),
|
55 |
+
'free-trial' => _fs_text( 'Free Trial' ),
|
56 |
+
'start-free-x' => _fs_text( 'Start my free %s' ),
|
57 |
+
'no-commitment-x' => _fs_text( 'No commitment for %s - cancel anytime' ),
|
58 |
+
'after-x-pay-as-little-y' => _fs_text( 'After your free %s, pay as little as %s' ),
|
59 |
+
'details' => _fs_text( 'Details' ),
|
60 |
+
'account-details' => _fs_text( 'Account Details' ),
|
61 |
+
'delete' => _fs_x( 'Delete', 'verb' ),
|
62 |
+
'show' => _fs_x( 'Show', 'verb' ),
|
63 |
+
'hide' => _fs_x( 'Hide', 'verb' ),
|
64 |
+
'edit' => _fs_x( 'Edit', 'verb' ),
|
65 |
+
'update' => _fs_x( 'Update', 'verb' ),
|
66 |
+
'date' => _fs_text( 'Date' ),
|
67 |
+
'amount' => _fs_text( 'Amount' ),
|
68 |
+
'invoice' => _fs_text( 'Invoice' ),
|
69 |
+
'billing' => _fs_text( 'Billing' ),
|
70 |
+
'payments' => _fs_text( 'Payments' ),
|
71 |
+
'delete-account' => _fs_text( 'Delete Account' ),
|
72 |
+
'dismiss' => _fs_x( 'Dismiss', 'as close a window' ),
|
73 |
+
'plan' => _fs_x( 'Plan', 'as product pricing plan' ),
|
74 |
+
'change-plan' => _fs_text( 'Change Plan' ),
|
75 |
+
'download-x-version' => _fs_x( 'Download %s Version', 'as download professional version' ),
|
76 |
+
'download-x-version-now' => _fs_x( 'Download %s version now', 'as download professional version now' ),
|
77 |
+
'download-latest' => _fs_x( 'Download Latest', 'as download latest version' ),
|
78 |
+
'you-have-x-license' => _fs_x( 'You have a %s license.', 'E.g. you have a professional license.' ),
|
79 |
+
'new' => _fs_text( 'New' ),
|
80 |
+
'free' => _fs_text( 'Free' ),
|
81 |
+
'trial' => _fs_x( 'Trial', 'as trial plan' ),
|
82 |
+
'start-trial' => _fs_x( 'Start Trial', 'as starting a trial plan' ),
|
83 |
+
'purchase' => _fs_x( 'Purchase', 'verb' ),
|
84 |
+
'purchase-license' => _fs_text( 'Purchase License' ),
|
85 |
+
'buy' => _fs_x( 'Buy', 'verb' ),
|
86 |
+
'buy-license' => _fs_text( 'Buy License' ),
|
87 |
+
'license-single-site' => _fs_text( 'Single Site License' ),
|
88 |
+
'license-unlimited' => _fs_text( 'Unlimited Licenses' ),
|
89 |
+
'license-x-sites' => _fs_text( 'Up to %s Sites' ),
|
90 |
+
'renew-license-now' => _fs_text( '%sRenew your license now%s to access version %s security & feature updates, and support.' ),
|
91 |
+
'ask-for-upgrade-email-address' => _fs_text( "Enter the email address you've used for the upgrade below and we will resend you the license key." ),
|
92 |
+
'x-plan' => _fs_x( '%s Plan', 'e.g. Professional Plan' ),
|
93 |
+
'you-are-step-away' => _fs_text( 'You are just one step away - %s' ),
|
94 |
+
'activate-x-now' => _fs_x( 'Complete "%s" Activation Now',
|
95 |
+
'%s - plugin name. As complete "Jetpack" activation now' ),
|
96 |
+
'few-plugin-tweaks' => _fs_text( 'We made a few tweaks to the %s, %s' ),
|
97 |
+
'optin-x-now' => _fs_text( 'Opt in to make "%s" better!' ),
|
98 |
+
'error' => _fs_text( 'Error' ),
|
99 |
+
'failed-finding-main-path' => _fs_text( 'Freemius SDK couldn\'t find the plugin\'s main file. Please contact sdk@freemius.com with the current error.' ),
|
100 |
+
'learn-more' => _fs_text( 'Learn more' ),
|
101 |
+
'license_not_whitelabeled' => _fs_text( "Is this your client's site? %s if you wish to hide sensitive info like your billing address and invoices from the WP Admin."),
|
102 |
+
'license_whitelabeled' => _fs_text( 'Your %s license was flagged as white-labeled to hide sensitive information from the WP Admin (e.g. your billing address and 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.'),
|
103 |
+
|
104 |
+
#region Affiliation
|
105 |
+
'affiliation' => _fs_text( 'Affiliation' ),
|
106 |
+
'affiliate' => _fs_text( 'Affiliate' ),
|
107 |
+
'affiliate-tracking' => _fs_text( '%s tracking cookie after the first visit to maximize earnings potential.' ),
|
108 |
+
'renewals-commission' => _fs_text( 'Get commission for automated subscription renewals.' ),
|
109 |
+
'affiliate-application-accepted' => _fs_text( "Your affiliate application for %s has been accepted! Log in to your affiliate area at: %s." ),
|
110 |
+
'affiliate-application-thank-you' => _fs_text( "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." ),
|
111 |
+
'affiliate-application-rejected' => _fs_text( "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." ),
|
112 |
+
'affiliate-account-suspended' => _fs_text( 'Your affiliation account was temporarily suspended.' ),
|
113 |
+
'affiliate-account-blocked' => _fs_text( 'Due to violation of our affiliation terms, we decided to temporarily block your affiliation account. If you have any questions, please contact support.' ),
|
114 |
+
'become-an-ambassador' => _fs_text( 'Like the %s? Become our ambassador and earn cash ;-)' ),
|
115 |
+
'become-an-ambassador-admin-notice' => _fs_text( '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!' ),
|
116 |
+
'refer-new-customers' => _fs_text( 'Refer new customers to our %s and earn %s commission on each successful sale you refer!' ),
|
117 |
+
'program-summary' => _fs_text( 'Program Summary' ),
|
118 |
+
'commission-on-new-license-purchase' => _fs_text( '%s commission when a customer purchases a new license.' ),
|
119 |
+
'unlimited-commissions' => _fs_text( 'Unlimited commissions.' ),
|
120 |
+
'minimum-payout-amount' => _fs_text( '%s minimum payout amount.' ),
|
121 |
+
'payouts-unit-and-processing' => _fs_text( 'Payouts are in USD and processed monthly via PayPal.' ),
|
122 |
+
'commission-payment' => _fs_text( 'As we reserve 30 days for potential refunds, we only pay commissions that are older than 30 days.' ),
|
123 |
+
'become-an-affiliate' => _fs_text( 'Become an affiliate' ),
|
124 |
+
'apply-to-become-an-affiliate' => _fs_text( 'Apply to become an affiliate' ),
|
125 |
+
'full-name' => _fs_text( 'Full name' ),
|
126 |
+
'paypal-account-email-address' => _fs_text( 'PayPal account email address' ),
|
127 |
+
'promotion-methods' => _fs_text( 'Promotion methods' ),
|
128 |
+
'social-media' => _fs_text( 'Social media (Facebook, Twitter, etc.)' ),
|
129 |
+
'mobile-apps' => _fs_text( 'Mobile apps' ),
|
130 |
+
'statistics-information-field-label' => _fs_text( 'Website, email, and social media statistics (optional)' ),
|
131 |
+
'statistics-information-field-desc' => _fs_text( '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).' ),
|
132 |
+
'promotion-method-desc-field-label' => _fs_text( 'How will you promote us?' ),
|
133 |
+
'promotion-method-desc-field-desc' => _fs_text( 'Please provide details on how you intend to promote %s (please be as specific as possible).' ),
|
134 |
+
'domain-field-label' => _fs_text( 'Where are you going to promote the %s?' ),
|
135 |
+
'domain-field-desc' => _fs_text( 'Enter the domain of your website or other websites from where you plan to promote the %s.' ),
|
136 |
+
'extra-domain-fields-label' => _fs_text( 'Extra Domains' ),
|
137 |
+
'extra-domain-fields-desc' => _fs_text( 'Extra domains where you will be marketing the product from.' ),
|
138 |
+
'add-another-domain' => _fs_text( 'Add another domain' ),
|
139 |
+
'remove' => _fs_x( 'Remove', 'Remove domain' ),
|
140 |
+
'email-address-is-required' => _fs_text( 'Email address is required.' ),
|
141 |
+
'domain-is-required' => _fs_text( 'Domain is required.' ),
|
142 |
+
'invalid-domain' => _fs_text( 'Invalid domain' ),
|
143 |
+
'paypal-email-address-is-required' => _fs_text( 'PayPal email address is required.' ),
|
144 |
+
'processing' => _fs_text( 'Processing...' ),
|
145 |
+
'non-expiring' => _fs_text( 'Non-expiring' ),
|
146 |
+
'account-is-pending-activation' => _fs_text( 'Account is pending activation.' ),
|
147 |
+
#endregion Affiliation
|
148 |
+
|
149 |
+
#region Account
|
150 |
+
'expiration' => _fs_x( 'Expiration', 'as expiration date' ),
|
151 |
+
'license' => _fs_x( 'License', 'as software license' ),
|
152 |
+
'not-verified' => _fs_text( 'not verified' ),
|
153 |
+
'verify-email' => _fs_text( 'Verify Email' ),
|
154 |
+
'expires-in' => _fs_x( 'Expires in %s', 'e.g. expires in 2 months' ),
|
155 |
+
'renews-in' => _fs_x( 'Auto renews in %s', 'e.g. auto renews in 2 months' ),
|
156 |
+
'no-expiration' => _fs_text( 'No expiration' ),
|
157 |
+
'expired' => _fs_text( 'Expired' ),
|
158 |
+
'cancelled' => _fs_text( 'Cancelled' ),
|
159 |
+
'in-x' => _fs_x( 'In %s', 'e.g. In 2 hours' ),
|
160 |
+
'x-ago' => _fs_x( '%s ago', 'e.g. 2 min ago' ),
|
161 |
+
/* translators: %s: Version number (e.g. 4.6 or higher) */
|
162 |
+
'x-or-higher' => _fs_text( '%s or higher' ),
|
163 |
+
'version' => _fs_x( 'Version', 'as plugin version' ),
|
164 |
+
'name' => _fs_text( 'Name' ),
|
165 |
+
'email' => _fs_text( 'Email' ),
|
166 |
+
'email-address' => _fs_text( 'Email address' ),
|
167 |
+
'verified' => _fs_text( 'Verified' ),
|
168 |
+
'module' => _fs_text( 'Module' ),
|
169 |
+
'module-type' => _fs_text( 'Module Type' ),
|
170 |
+
'plugin' => _fs_text( 'Plugin' ),
|
171 |
+
'plugins' => _fs_text( 'Plugins' ),
|
172 |
+
'theme' => _fs_text( 'Theme' ),
|
173 |
+
'themes' => _fs_text( 'Themes' ),
|
174 |
+
'path' => _fs_x( 'Path', 'as file/folder path' ),
|
175 |
+
'title' => _fs_text( 'Title' ),
|
176 |
+
'free-version' => _fs_text( 'Free version' ),
|
177 |
+
'premium-version' => _fs_text( 'Premium version' ),
|
178 |
+
'slug' => _fs_x( 'Slug', 'as WP plugin slug' ),
|
179 |
+
'id' => _fs_text( 'ID' ),
|
180 |
+
'users' => _fs_text( 'Users' ),
|
181 |
+
'module-installs' => _fs_text( '%s Installs' ),
|
182 |
+
'sites' => _fs_x( 'Sites', 'like websites' ),
|
183 |
+
'user-id' => _fs_text( 'User ID' ),
|
184 |
+
'site-id' => _fs_text( 'Site ID' ),
|
185 |
+
'public-key' => _fs_text( 'Public Key' ),
|
186 |
+
'secret-key' => _fs_text( 'Secret Key' ),
|
187 |
+
'no-secret' => _fs_x( 'No Secret', 'as secret encryption key missing' ),
|
188 |
+
'no-id' => _fs_text( 'No ID' ),
|
189 |
+
'sync-license' => _fs_x( 'Sync License', 'as synchronize license' ),
|
190 |
+
'sync' => _fs_x( 'Sync', 'as synchronize' ),
|
191 |
+
'activate-license' => _fs_text( 'Activate License' ),
|
192 |
+
'activate-free-version' => _fs_text( 'Activate Free Version' ),
|
193 |
+
'activate-license-message' => _fs_text( 'Please enter the license key that you received in the email right after the purchase:' ),
|
194 |
+
'activating-license' => _fs_text( 'Activating license...' ),
|
195 |
+
'change-license' => _fs_text( 'Change License' ),
|
196 |
+
'update-license' => _fs_text( 'Update License' ),
|
197 |
+
'deactivate-license' => _fs_text( 'Deactivate License' ),
|
198 |
+
'activate' => _fs_text( 'Activate' ),
|
199 |
+
'deactivate' => _fs_text( 'Deactivate' ),
|
200 |
+
'skip-deactivate' => _fs_text( 'Skip & Deactivate' ),
|
201 |
+
'skip-and-x' => _fs_text( 'Skip & %s' ),
|
202 |
+
'no-deactivate' => _fs_text( 'No - just deactivate' ),
|
203 |
+
'yes-do-your-thing' => _fs_text( 'Yes - do your thing' ),
|
204 |
+
'active' => _fs_x( 'Active', 'active mode' ),
|
205 |
+
'is-active' => _fs_x( 'Is Active', 'is active mode?' ),
|
206 |
+
'install-now' => _fs_text( 'Install Now' ),
|
207 |
+
'install-update-now' => _fs_text( 'Install Update Now' ),
|
208 |
+
'more-information-about-x' => _fs_text( 'More information about %s' ),
|
209 |
+
'localhost' => _fs_text( 'Localhost' ),
|
210 |
+
'activate-x-plan' => _fs_x( 'Activate %s Plan', 'as activate Professional plan' ),
|
211 |
+
'x-left' => _fs_x( '%s left', 'as 5 licenses left' ),
|
212 |
+
'last-license' => _fs_text( 'Last license' ),
|
213 |
+
'what-is-your-x' => _fs_text( 'What is your %s?' ),
|
214 |
+
'activate-this-addon' => _fs_text( 'Activate this add-on' ),
|
215 |
+
'deactivate-license-confirm' => _fs_text( 'Deactivating your license will block all premium features, but will enable you to activate the license on another site. Are you sure you want to proceed?' ),
|
216 |
+
'delete-account-x-confirm' => _fs_text( '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?' ),
|
217 |
+
'delete-account-confirm' => _fs_text( '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?' ),
|
218 |
+
'downgrade-x-confirm' => _fs_text( 'Downgrading your plan will immediately stop all future recurring payments and your %s plan license will expire in %s.' ),
|
219 |
+
'cancel-trial-confirm' => _fs_text( 'Cancelling the trial will immediately block access to all premium features. Are you sure?' ),
|
220 |
+
'after-downgrade-non-blocking' => _fs_text( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.' ),
|
221 |
+
'after-downgrade-blocking' => _fs_text( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.' ),
|
222 |
+
'proceed-confirmation' => _fs_text( 'Are you sure you want to proceed?' ),
|
223 |
+
#endregion Account
|
224 |
+
|
225 |
+
'add-ons-for-x' => _fs_text( 'Add Ons for %s' ),
|
226 |
+
'add-ons-missing' => _fs_text( 'We could\'nt load the add-ons list. It\'s probably an issue on our side, please try to come back in few minutes.' ),
|
227 |
+
#region Plugin Deactivation
|
228 |
+
'anonymous-feedback' => _fs_text( 'Anonymous feedback' ),
|
229 |
+
'quick-feedback' => _fs_text( 'Quick feedback' ),
|
230 |
+
'deactivation-share-reason' => _fs_text( 'If you have a moment, please let us know why you are %s' ),
|
231 |
+
'deactivating' => _fs_text( 'deactivating' ),
|
232 |
+
'deactivation' => _fs_text( 'Deactivation' ),
|
233 |
+
'theme-switch' => _fs_text( 'Theme Switch' ),
|
234 |
+
'switching' => _fs_text( 'switching' ),
|
235 |
+
'switch' => _fs_text( 'Switch' ),
|
236 |
+
'activate-x' => _fs_text( 'Activate %s' ),
|
237 |
+
'deactivation-modal-button-confirm' => _fs_text( 'Yes - %s' ),
|
238 |
+
'deactivation-modal-button-submit' => _fs_text( 'Submit & %s' ),
|
239 |
+
'cancel' => _fs_text( 'Cancel' ),
|
240 |
+
'reason-no-longer-needed' => _fs_text( 'I no longer need the %s' ),
|
241 |
+
'reason-found-a-better-plugin' => _fs_text( 'I found a better %s' ),
|
242 |
+
'reason-needed-for-a-short-period' => _fs_text( 'I only needed the %s for a short period' ),
|
243 |
+
'reason-broke-my-site' => _fs_text( 'The %s broke my site' ),
|
244 |
+
'reason-suddenly-stopped-working' => _fs_text( 'The %s suddenly stopped working' ),
|
245 |
+
'reason-cant-pay-anymore' => _fs_text( "I can't pay for it anymore" ),
|
246 |
+
'reason-temporary-deactivation' => _fs_text( "It's a temporary deactivation. I'm just debugging an issue." ),
|
247 |
+
'reason-temporary-x' => _fs_text( "It's a temporary %s. I'm just debugging an issue." ),
|
248 |
+
'reason-other' => _fs_x( 'Other',
|
249 |
+
'the text of the "other" reason for deactivating the module that is shown in the modal box.' ),
|
250 |
+
'ask-for-reason-message' => _fs_text( 'Kindly tell us the reason so we can improve.' ),
|
251 |
+
'placeholder-plugin-name' => _fs_text( "What's the %s's name?" ),
|
252 |
+
'placeholder-comfortable-price' => _fs_text( 'What price would you feel comfortable paying?' ),
|
253 |
+
'reason-couldnt-make-it-work' => _fs_text( "I couldn't understand how to make it work" ),
|
254 |
+
'reason-great-but-need-specific-feature' => _fs_text( "The %s is great, but I need specific feature that you don't support" ),
|
255 |
+
'reason-not-working' => _fs_text( 'The %s is not working' ),
|
256 |
+
'reason-not-what-i-was-looking-for' => _fs_text( "It's not what I was looking for" ),
|
257 |
+
'reason-didnt-work-as-expected' => _fs_text( "The %s didn't work as expected" ),
|
258 |
+
'placeholder-feature' => _fs_text( 'What feature?' ),
|
259 |
+
'placeholder-share-what-didnt-work' => _fs_text( "Kindly share what didn't work so we can fix it for future users..." ),
|
260 |
+
'placeholder-what-youve-been-looking-for' => _fs_text( "What you've been looking for?" ),
|
261 |
+
'placeholder-what-did-you-expect' => _fs_text( "What did you expect?" ),
|
262 |
+
'reason-didnt-work' => _fs_text( "The %s didn't work" ),
|
263 |
+
'reason-dont-like-to-share-my-information' => _fs_text( "I don't like to share my information with you" ),
|
264 |
+
'dont-have-to-share-any-data' => _fs_text( "You might have missed it, but you don't have to share any data and can just %s the opt-in." ),
|
265 |
+
#endregion Plugin Deactivation
|
266 |
+
|
267 |
+
#region Connect
|
268 |
+
'hey-x' => _fs_x( 'Hey %s,', 'greeting' ),
|
269 |
+
'thanks-x' => _fs_x( 'Thanks %s!', 'a greeting. E.g. Thanks John!' ),
|
270 |
+
'connect-message' => _fs_text( 'Never miss an important update - opt in to our security and feature updates notifications, and non-sensitive diagnostic tracking with %4$s.' ),
|
271 |
+
'connect-message_on-update' => _fs_text( 'Please help us improve %1$s! If you opt in, some data about your usage of %1$s will be sent to %4$s. If you skip this, that\'s okay! %1$s will still work just fine.' ),
|
272 |
+
'pending-activation-message' => _fs_text( '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.' ),
|
273 |
+
'complete-the-install' => _fs_text( 'complete the install' ),
|
274 |
+
'start-the-trial' => _fs_text( 'start the trial' ),
|
275 |
+
'thanks-for-purchasing' => _fs_text( 'Thanks for purchasing %s! To get started, please enter your license key:' ),
|
276 |
+
'license-sync-disclaimer' => _fs_text( '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.' ),
|
277 |
+
'what-permissions' => _fs_text( 'What permissions are being granted?' ),
|
278 |
+
'permissions-profile' => _fs_text( 'Your Profile Overview' ),
|
279 |
+
'permissions-profile_desc' => _fs_text( 'Name and email address' ),
|
280 |
+
'permissions-site' => _fs_text( 'Your Site Overview' ),
|
281 |
+
'permissions-site_desc' => _fs_text( 'Site URL, WP version, PHP info, plugins & themes' ),
|
282 |
+
'permissions-events' => _fs_text( 'Current %s Events' ),
|
283 |
+
'permissions-events_desc' => _fs_text( 'Activation, deactivation and uninstall' ),
|
284 |
+
'permissions-plugins_themes' => _fs_text( 'Plugins & Themes' ),
|
285 |
+
'permissions-plugins_themes_desc' => _fs_text( 'Titles, versions and state.' ),
|
286 |
+
'permissions-admin-notices' => _fs_text( 'Admin Notices' ),
|
287 |
+
'permissions-newsletter' => _fs_text( 'Newsletter' ),
|
288 |
+
'permissions-newsletter_desc' => _fs_text( 'Updates, announcements, marketing, no spam' ),
|
289 |
+
'privacy-policy' => _fs_text( 'Privacy Policy' ),
|
290 |
+
'tos' => _fs_text( 'Terms of Service' ),
|
291 |
+
'activating' => _fs_x( 'Activating', 'as activating plugin' ),
|
292 |
+
'sending-email' => _fs_x( 'Sending email', 'as in the process of sending an email' ),
|
293 |
+
'opt-in-connect' => _fs_x( 'Allow & Continue', 'button label' ),
|
294 |
+
'agree-activate-license' => _fs_x( 'Agree & Activate License', 'button label' ),
|
295 |
+
'skip' => _fs_x( 'Skip', 'verb' ),
|
296 |
+
'click-here-to-use-plugin-anonymously' => _fs_text( 'Click here to use the plugin anonymously' ),
|
297 |
+
'resend-activation-email' => _fs_text( 'Re-send activation email' ),
|
298 |
+
'license-key' => _fs_text( 'License key' ),
|
299 |
+
'send-license-key' => _fs_text( 'Send License Key' ),
|
300 |
+
'sending-license-key' => _fs_text( 'Sending license key' ),
|
301 |
+
'have-license-key' => _fs_text( 'Have a license key?' ),
|
302 |
+
'dont-have-license-key' => _fs_text( 'Don\'t have a license key?' ),
|
303 |
+
'cant-find-license-key' => _fs_text( "Can't find your license key?" ),
|
304 |
+
'email-not-found' => _fs_text( "We couldn't find your email address in the system, are you sure it's the right address?" ),
|
305 |
+
'no-active-licenses' => _fs_text( "We can't see any active licenses associated with that email address, are you sure it's the right address?" ),
|
306 |
+
'opt-in' => _fs_text( 'Opt In' ),
|
307 |
+
'opt-out' => _fs_text( 'Opt Out' ),
|
308 |
+
'opt-out-cancel' => _fs_text( 'On second thought - I want to continue helping' ),
|
309 |
+
'opting-out' => _fs_text( 'Opting out...' ),
|
310 |
+
'opting-in' => _fs_text( 'Opting in...' ),
|
311 |
+
'opt-out-message-appreciation' => _fs_text( 'We appreciate your help in making the %s better by letting us track some usage data.' ),
|
312 |
+
'opt-out-message-usage-tracking' => _fs_text( "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." ),
|
313 |
+
'opt-out-message-clicking-opt-out' => _fs_text( 'By clicking "Opt Out", we will no longer be sending any data from %s to %s.' ),
|
314 |
+
'apply-on-all-sites-in-the-network' => _fs_text( 'Apply on all sites in the network.' ),
|
315 |
+
'delegate-to-site-admins' => _fs_text( 'Delegate to Site Admins' ),
|
316 |
+
'delegate-to-site-admins-and-continue' => _fs_text( 'Delegate to Site Admins & Continue' ),
|
317 |
+
'continue' => _fs_text( 'Continue' ),
|
318 |
+
'allow' => _fs_text( 'allow' ),
|
319 |
+
'delegate' => _fs_text( 'delegate' ),
|
320 |
+
#endregion Connect
|
321 |
+
|
322 |
+
#region Screenshots
|
323 |
+
'screenshots' => _fs_text( 'Screenshots' ),
|
324 |
+
'view-full-size-x' => _fs_text( 'Click to view full-size screenshot %d' ),
|
325 |
+
#endregion Screenshots
|
326 |
+
|
327 |
+
#region Debug
|
328 |
+
'freemius-debug' => _fs_text( 'Freemius Debug' ),
|
329 |
+
'on' => _fs_x( 'On', 'as turned on' ),
|
330 |
+
'off' => _fs_x( 'Off', 'as turned off' ),
|
331 |
+
'debugging' => _fs_x( 'Debugging', 'as code debugging' ),
|
332 |
+
'freemius-state' => _fs_text( 'Freemius State' ),
|
333 |
+
'connected' => _fs_x( 'Connected', 'as connection was successful' ),
|
334 |
+
'blocked' => _fs_x( 'Blocked', 'as connection blocked' ),
|
335 |
+
'api' => _fs_x( 'API', 'as application program interface' ),
|
336 |
+
'sdk' => _fs_x( 'SDK', 'as software development kit versions' ),
|
337 |
+
'sdk-versions' => _fs_x( 'SDK Versions', 'as software development kit versions' ),
|
338 |
+
'plugin-path' => _fs_x( 'Plugin Path', 'as plugin folder path' ),
|
339 |
+
'sdk-path' => _fs_x( 'SDK Path', 'as sdk path' ),
|
340 |
+
'addons-of-x' => _fs_text( 'Add Ons of Plugin %s' ),
|
341 |
+
'delete-all-confirm' => _fs_text( 'Are you sure you want to delete all Freemius data?' ),
|
342 |
+
'actions' => _fs_text( 'Actions' ),
|
343 |
+
'delete-all-accounts' => _fs_text( 'Delete All Accounts' ),
|
344 |
+
'start-fresh' => _fs_text( 'Start Fresh' ),
|
345 |
+
'clear-api-cache' => _fs_text( 'Clear API Cache' ),
|
346 |
+
'sync-data-from-server' => _fs_text( 'Sync Data From Server' ),
|
347 |
+
'scheduled-crons' => _fs_text( 'Scheduled Crons' ),
|
348 |
+
'cron-type' => _fs_text( 'Cron Type' ),
|
349 |
+
'plugins-themes-sync' => _fs_text( 'Plugins & Themes Sync' ),
|
350 |
+
'module-licenses' => _fs_text( '%s Licenses' ),
|
351 |
+
'debug-log' => _fs_text( 'Debug Log' ),
|
352 |
+
'all' => _fs_text( 'All' ),
|
353 |
+
'file' => _fs_text( 'File' ),
|
354 |
+
'function' => _fs_text( 'Function' ),
|
355 |
+
'process-id' => _fs_text( 'Process ID' ),
|
356 |
+
'logger' => _fs_text( 'Logger' ),
|
357 |
+
'message' => _fs_text( 'Message' ),
|
358 |
+
'download' => _fs_text( 'Download' ),
|
359 |
+
'filter' => _fs_text( 'Filter' ),
|
360 |
+
'type' => _fs_text( 'Type' ),
|
361 |
+
'all-types' => _fs_text( 'All Types' ),
|
362 |
+
'all-requests' => _fs_text( 'All Requests' ),
|
363 |
+
#endregion Debug
|
364 |
+
|
365 |
+
#region Expressions
|
366 |
+
'congrats' => _fs_x( 'Congrats', 'as congratulations' ),
|
367 |
+
'oops' => _fs_x( 'Oops', 'exclamation' ),
|
368 |
+
'yee-haw' => _fs_x( 'Yee-haw', 'interjection expressing joy or exuberance' ),
|
369 |
+
'woot' => _fs_x( 'W00t',
|
370 |
+
'(especially in electronic communication) used to express elation, enthusiasm, or triumph.' ),
|
371 |
+
'right-on' => _fs_x( 'Right on', 'a positive response' ),
|
372 |
+
'hmm' => _fs_x( 'Hmm',
|
373 |
+
'something somebody says when they are thinking about what you have just said. ' ),
|
374 |
+
'ok' => _fs_text( 'O.K' ),
|
375 |
+
'hey' => _fs_x( 'Hey', 'exclamation' ),
|
376 |
+
'heads-up' => _fs_x( 'Heads up',
|
377 |
+
'advance notice of something that will need attention.' ),
|
378 |
+
#endregion Expressions
|
379 |
+
|
380 |
+
#region Admin Notices
|
381 |
+
'you-have-latest' => _fs_text( 'Seems like you got the latest release.' ),
|
382 |
+
'you-are-good' => _fs_text( 'You are all good!' ),
|
383 |
+
'user-exist-message' => _fs_text( 'Sorry, we could not complete the email update. Another user with the same email is already registered.' ),
|
384 |
+
'user-exist-message_ownership' => _fs_text( 'If you would like to give up the ownership of the %s\'s account to %s click the Change Ownership button.' ),
|
385 |
+
'email-updated-message' => _fs_text( 'Your email was successfully updated. You should receive an email with confirmation instructions in few moments.' ),
|
386 |
+
'name-updated-message' => _fs_text( 'Your name was successfully updated.' ),
|
387 |
+
'x-updated' => _fs_text( 'You have successfully updated your %s.' ),
|
388 |
+
'name-update-failed-message' => _fs_text( 'Please provide your full name.' ),
|
389 |
+
'verification-email-sent-message' => _fs_text( 'Verification mail was just sent to %s. If you can\'t find it after 5 min, please check your spam box.' ),
|
390 |
+
'addons-info-external-message' => _fs_text( 'Just letting you know that the add-ons information of %s is being pulled from an external server.' ),
|
391 |
+
'no-cc-required' => _fs_text( 'No credit card required' ),
|
392 |
+
'premium-activated-message' => _fs_text( 'Premium %s version was successfully activated.' ),
|
393 |
+
'successful-version-upgrade-message' => _fs_text( 'The upgrade of %s was successfully completed.' ),
|
394 |
+
'activation-with-plan-x-message' => _fs_text( 'Your account was successfully activated with the %s plan.' ),
|
395 |
+
'download-latest-x-version-now' => _fs_text( 'Download the latest %s version now' ),
|
396 |
+
'follow-steps-to-complete-upgrade' => _fs_text( 'Please follow these steps to complete the upgrade' ),
|
397 |
+
'download-latest-x-version' => _fs_text( 'Download the latest %s version' ),
|
398 |
+
'download-latest-version' => _fs_text( 'Download the latest version' ),
|
399 |
+
'deactivate-free-version' => _fs_text( 'Deactivate the free version' ),
|
400 |
+
'upload-and-activate' => _fs_text( 'Upload and activate the downloaded version' ),
|
401 |
+
'howto-upload-activate' => _fs_text( 'How to upload and activate?' ),
|
402 |
+
'addon-successfully-purchased-message' => _fs_x( '%s Add-on was successfully purchased.',
|
403 |
+
'%s - product name, e.g. Facebook add-on was successfully...' ),
|
404 |
+
'addon-successfully-upgraded-message' => _fs_text( 'Your %s Add-on plan was successfully upgraded.' ),
|
405 |
+
'email-verified-message' => _fs_text( 'Your email has been successfully verified - you are AWESOME!' ),
|
406 |
+
'plan-upgraded-message' => _fs_text( 'Your plan was successfully upgraded.' ),
|
407 |
+
'plan-changed-to-x-message' => _fs_text( 'Your plan was successfully changed to %s.' ),
|
408 |
+
'license-expired-blocking-message' => _fs_text( 'Your license has expired. You can still continue using the free %s forever.' ),
|
409 |
+
'license-cancelled' => _fs_text( 'Your license has been cancelled. If you think it\'s a mistake, please contact support.' ),
|
410 |
+
'trial-started-message' => _fs_text( 'Your trial has been successfully started.' ),
|
411 |
+
'license-activated-message' => _fs_text( 'Your license was successfully activated.' ),
|
412 |
+
'no-active-license-message' => _fs_text( 'It looks like your site currently doesn\'t have an active license.' ),
|
413 |
+
'license-deactivation-message' => _fs_text( 'Your license was successfully deactivated, you are back to the %s plan.' ),
|
414 |
+
'license-deactivation-failed-message' => _fs_text( 'It looks like the license deactivation failed.' ),
|
415 |
+
'license-activation-failed-message' => _fs_text( 'It looks like the license could not be activated.' ),
|
416 |
+
'server-error-message' => _fs_text( 'Error received from the server:' ),
|
417 |
+
'trial-expired-message' => _fs_text( 'Your trial has expired. You can still continue using all our free features.' ),
|
418 |
+
'plan-x-downgraded-message' => _fs_text( 'Your plan was successfully downgraded. Your %s plan license will expire in %s.' ),
|
419 |
+
'plan-downgraded-failure-message' => _fs_text( 'Seems like we are having some temporary issue with your plan downgrade. Please try again in few minutes.' ),
|
420 |
+
'trial-cancel-no-trial-message' => _fs_text( 'It looks like you are not in trial mode anymore so there\'s nothing to cancel :)' ),
|
421 |
+
'trial-cancel-message' => _fs_text( 'Your %s free trial was successfully cancelled.' ),
|
422 |
+
'version-x-released' => _fs_x( 'Version %s was released.', '%s - numeric version number' ),
|
423 |
+
'please-download-x' => _fs_text( 'Please download %s.' ),
|
424 |
+
'latest-x-version' => _fs_x( 'the latest %s version here',
|
425 |
+
'%s - plan name, as the latest professional version here' ),
|
426 |
+
'trial-x-promotion-message' => _fs_text( 'How do you like %s so far? Test all our %s premium features with a %d-day free trial.' ),
|
427 |
+
'start-free-trial' => _fs_x( 'Start free trial', 'call to action' ),
|
428 |
+
'starting-trial' => _fs_text( 'Starting trial' ),
|
429 |
+
'please-wait' => _fs_text( 'Please wait' ),
|
430 |
+
'trial-cancel-failure-message' => _fs_text( 'Seems like we are having some temporary issue with your trial cancellation. Please try again in few minutes.' ),
|
431 |
+
'trial-utilized' => _fs_text( 'You already utilized a trial before.' ),
|
432 |
+
'in-trial-mode' => _fs_text( 'You are already running the %s in a trial mode.' ),
|
433 |
+
'trial-plan-x-not-exist' => _fs_text( 'Plan %s do not exist, therefore, can\'t start a trial.' ),
|
434 |
+
'plan-x-no-trial' => _fs_text( 'Plan %s does not support a trial period.' ),
|
435 |
+
'no-trials' => _fs_text( 'None of the %s\'s plans supports a trial period.' ),
|
436 |
+
'unexpected-api-error' => _fs_text( 'Unexpected API error. Please contact the %s\'s author with the following error.' ),
|
437 |
+
'no-commitment-for-x-days' => _fs_text( 'No commitment for %s days - cancel anytime!' ),
|
438 |
+
'license-expired-non-blocking-message' => _fs_text( '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.' ),
|
439 |
+
'could-not-activate-x' => _fs_text( 'Couldn\'t activate %s.' ),
|
440 |
+
'contact-us-with-error-message' => _fs_text( 'Please contact us with the following message:' ),
|
441 |
+
'plan-did-not-change-message' => _fs_text( '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.' ),
|
442 |
+
'contact-us-here' => _fs_text( 'Please contact us here' ),
|
443 |
+
'plan-did-not-change-email-message' => _fs_text( 'I have upgraded my account but when I try to Sync the License, the plan remains %s.' ),
|
444 |
+
#endregion Admin Notices
|
445 |
+
#region Connectivity Issues
|
446 |
+
'connectivity-test-fails-message' => _fs_text( 'From unknown reason, the API connectivity test failed.' ),
|
447 |
+
'connectivity-test-maybe-temporary' => _fs_text( 'It\'s probably a temporary issue on our end. Just to be sure, with your permission, would it be o.k to run another connectivity test?' ),
|
448 |
+
'curl-missing-message' => _fs_text( 'We use PHP cURL library for the API calls, which is a very common library and usually installed and activated out of the box. Unfortunately, cURL is not activated (or disabled) on your server.' ),
|
449 |
+
'curl-disabled-methods' => _fs_text( 'Disabled method(s):' ),
|
450 |
+
'cloudflare-blocks-connection-message' => _fs_text( 'From unknown reason, CloudFlare, the firewall we use, blocks the connection.' ),
|
451 |
+
'x-requires-access-to-api' => _fs_x( '%s requires an access to our API.',
|
452 |
+
'as pluginX requires an access to our API' ),
|
453 |
+
'squid-blocks-connection-message' => _fs_text( 'It looks like your server is using Squid ACL (access control lists), which blocks the connection.' ),
|
454 |
+
'squid-no-clue-title' => _fs_text( 'I don\'t know what is Squid or ACL, help me!' ),
|
455 |
+
'squid-no-clue-desc' => _fs_text( '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.' ),
|
456 |
+
'sysadmin-title' => _fs_text( 'I\'m a system administrator' ),
|
457 |
+
'squid-sysadmin-desc' => _fs_text( 'Great, please whitelist the following domains: %s. Once you are done, deactivate the %s and activate it again.' ),
|
458 |
+
'curl-missing-no-clue-title' => _fs_text( 'I don\'t know what is cURL or how to install it, help me!' ),
|
459 |
+
'curl-missing-no-clue-desc' => _fs_text( '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.' ),
|
460 |
+
'curl-missing-sysadmin-desc' => _fs_text( '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.' ),
|
461 |
+
'happy-to-resolve-issue-asap' => _fs_text( '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.' ),
|
462 |
+
'contact-support-before-deactivation' => _fs_text( 'Sorry for the inconvenience and we are here to help if you give us a chance.' ),
|
463 |
+
'fix-issue-title' => _fs_text( 'Yes - I\'m giving you a chance to fix it' ),
|
464 |
+
'fix-issue-desc' => _fs_text( '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.' ),
|
465 |
+
'install-previous-title' => _fs_text( 'Let\'s try your previous version' ),
|
466 |
+
'install-previous-desc' => _fs_text( 'Uninstall this version and install the previous one.' ),
|
467 |
+
'deactivate-plugin-title' => _fs_text( 'That\'s exhausting, please deactivate' ),
|
468 |
+
'deactivate-plugin-desc' => _fs_text( 'We feel your frustration and sincerely apologize for the inconvenience. Hope to see you again in the future.' ),
|
469 |
+
'fix-request-sent-message' => _fs_text( '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.' ),
|
470 |
+
'server-blocking-access' => _fs_x( 'Your server is blocking the access to Freemius\' API, which is crucial for %1$s synchronization. Please contact your host to whitelist %2$s',
|
471 |
+
'%1$s - plugin title, %2$s - API domain' ),
|
472 |
+
'wrong-authentication-param-message' => _fs_text( 'It seems like one of the authentication parameters is wrong. Update your Public Key, Secret Key & User ID, and try again.' ),
|
473 |
+
#endregion Connectivity Issues
|
474 |
+
#region Change Owner
|
475 |
+
'change-owner-request-sent-x' => _fs_text( '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.' ),
|
476 |
+
'change-owner-request_owner-confirmed' => _fs_text( 'Thanks for confirming the ownership change. An email was just sent to %s for final approval.' ),
|
477 |
+
'change-owner-request_candidate-confirmed' => _fs_text( '%s is the new owner of the account.' ),
|
478 |
+
#endregion Change Owner
|
479 |
+
'addon-x-cannot-run-without-y' => _fs_x( '%s cannot run without %s.',
|
480 |
+
'addonX cannot run without pluginY' ),
|
481 |
+
'addon-x-cannot-run-without-parent' => _fs_x( '%s cannot run without the plugin.', 'addonX cannot run...' ),
|
482 |
+
'plugin-x-activation-message' => _fs_x( '%s activation was successfully completed.',
|
483 |
+
'pluginX activation was successfully...' ),
|
484 |
+
'features-and-pricing' => _fs_x( 'Features & Pricing', 'Plugin installer section title' ),
|
485 |
+
'free-addon-not-deployed' => _fs_text( 'Add-on must be deployed to WordPress.org or Freemius.' ),
|
486 |
+
'paid-addon-not-deployed' => _fs_text( 'Paid add-on must be deployed to Freemius.' ),
|
487 |
+
#--------------------------------------------------------------------------------
|
488 |
+
#region Add-On Licensing
|
489 |
+
#--------------------------------------------------------------------------------
|
490 |
+
'addon-no-license-message' => _fs_text( '%s is a premium only add-on. You have to purchase a license first before activating the plugin.' ),
|
491 |
+
'addon-trial-cancelled-message' => _fs_text( '%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.' ),
|
492 |
+
#endregion
|
493 |
+
#--------------------------------------------------------------------------------
|
494 |
+
#region Billing Cycles
|
495 |
+
#--------------------------------------------------------------------------------
|
496 |
+
'monthly' => _fs_x( 'Monthly', 'as every month' ),
|
497 |
+
'mo' => _fs_x( 'mo', 'as monthly period' ),
|
498 |
+
'annual' => _fs_x( 'Annual', 'as once a year' ),
|
499 |
+
'annually' => _fs_x( 'Annually', 'as once a year' ),
|
500 |
+
'once' => _fs_x( 'Once', 'as once a year' ),
|
501 |
+
'year' => _fs_x( 'year', 'as annual period' ),
|
502 |
+
'lifetime' => _fs_text( 'Lifetime' ),
|
503 |
+
'best' => _fs_x( 'Best', 'e.g. the best product' ),
|
504 |
+
'billed-x' => _fs_x( 'Billed %s', 'e.g. billed monthly' ),
|
505 |
+
'save-x' => _fs_x( 'Save %s', 'as a discount of $5 or 10%' ),
|
506 |
+
#endregion Billing Cycles
|
507 |
+
'view-details' => _fs_text( 'View details' ),
|
508 |
+
#--------------------------------------------------------------------------------
|
509 |
+
#region Trial
|
510 |
+
#--------------------------------------------------------------------------------
|
511 |
+
'approve-start-trial' => _fs_x( 'Approve & Start Trial', 'button label' ),
|
512 |
+
/* translators: %1$s: Number of trial days; %2$s: Plan name; */
|
513 |
+
'start-trial-prompt-header' => _fs_text( 'You are 1-click away from starting your %1$s-day free trial of the %2$s plan.' ),
|
514 |
+
/* translators: %s: Link to freemius.com */
|
515 |
+
'start-trial-prompt-message' => _fs_text( 'For compliance with the WordPress.org guidelines, before we start the trial we ask that you opt in with your user and non-sensitive site information, allowing the %s to periodically send data to %s to check for version updates and to validate your trial.' ),
|
516 |
+
|
517 |
+
#endregion
|
518 |
+
#--------------------------------------------------------------------------------
|
519 |
+
#region Billing Details
|
520 |
+
#--------------------------------------------------------------------------------
|
521 |
+
'business-name' => _fs_text( 'Business name' ),
|
522 |
+
'tax-vat-id' => _fs_text( 'Tax / VAT ID' ),
|
523 |
+
'address-line-n' => _fs_text( 'Address Line %d' ),
|
524 |
+
'country' => _fs_text( 'Country' ),
|
525 |
+
'select-country' => _fs_text( 'Select Country' ),
|
526 |
+
'city' => _fs_text( 'City' ),
|
527 |
+
'town' => _fs_text( 'Town' ),
|
528 |
+
'state' => _fs_text( 'State' ),
|
529 |
+
'province' => _fs_text( 'Province' ),
|
530 |
+
'zip-postal-code' => _fs_text( 'ZIP / Postal Code' ),
|
531 |
+
#endregion
|
532 |
+
#--------------------------------------------------------------------------------
|
533 |
+
#region Module Installation
|
534 |
+
#--------------------------------------------------------------------------------
|
535 |
+
'installing-plugin-x' => _fs_text( 'Installing plugin: %s' ),
|
536 |
+
'auto-installation' => _fs_text( 'Automatic Installation' ),
|
537 |
+
/* translators: %s: Number of seconds */
|
538 |
+
'x-sec' => _fs_text( '%s sec' ),
|
539 |
+
'installing-in-n' => _fs_text( 'An automated download and installation of %s (paid version) from %s will start in %s. If you would like to do it manually - click the cancellation button now.' ),
|
540 |
+
'installing-module-x' => _fs_text( 'The installation process has started and may take a few minutes to complete. Please wait until it is done - do not refresh this page.' ),
|
541 |
+
'cancel-installation' => _fs_text( 'Cancel Installation' ),
|
542 |
+
'module-package-rename-failure' => _fs_text( 'The remote plugin package does not contain a folder with the desired slug and renaming did not work.' ),
|
543 |
+
'auto-install-error-invalid-id' => _fs_text( 'Invalid module ID.' ),
|
544 |
+
'auto-install-error-not-opted-in' => _fs_text( 'Auto installation only works for opted-in users.' ),
|
545 |
+
'auto-install-error-premium-activated' => _fs_text( 'Premium version already active.' ),
|
546 |
+
'auto-install-error-premium-addon-activated' => _fs_text( 'Premium add-on version already installed.' ),
|
547 |
+
'auto-install-error-invalid-license' => _fs_text( 'You do not have a valid license to access the premium version.' ),
|
548 |
+
'auto-install-error-serviceware' => _fs_text( 'Plugin is a "Serviceware" which means it does not have a premium code version.' ),
|
549 |
+
#endregion
|
550 |
+
|
551 |
+
/* translators: %s: Page name */
|
552 |
+
'secure-x-page-header' => _fs_text( 'Secure HTTPS %s page, running from an external domain' ),
|
553 |
+
'pci-compliant' => _fs_text( 'PCI compliant' ),
|
554 |
+
'view-paid-features' => _fs_text( 'View paid features' ),
|
555 |
+
);
|
556 |
+
|
557 |
+
/**
|
558 |
+
* Localization of the strings in the plugin/theme info dialog box.
|
559 |
+
*
|
560 |
+
* $fs_module_info_text should ONLY include strings that are not located in $fs_text.
|
561 |
+
*
|
562 |
+
* @author Vova Feldman (@svovaf)
|
563 |
+
* @since 1.2.2
|
564 |
+
*/
|
565 |
+
global $fs_module_info_text;
|
566 |
+
|
567 |
+
$fs_module_info_text = array(
|
568 |
+
'description' => _fs_x( 'Description', 'Plugin installer section title' ),
|
569 |
+
'installation' => _fs_x( 'Installation', 'Plugin installer section title' ),
|
570 |
+
'faq' => _fs_x( 'FAQ', 'Plugin installer section title' ),
|
571 |
+
'changelog' => _fs_x( 'Changelog', 'Plugin installer section title' ),
|
572 |
+
'reviews' => _fs_x( 'Reviews', 'Plugin installer section title' ),
|
573 |
+
'other_notes' => _fs_x( 'Other Notes', 'Plugin installer section title' ),
|
574 |
+
/* translators: %s: 1 or One */
|
575 |
+
'x-star' => _fs_text( '%s star' ),
|
576 |
+
/* translators: %s: Number larger than 1 */
|
577 |
+
'x-stars' => _fs_text( '%s stars' ),
|
578 |
+
/* translators: %s: 1 or One */
|
579 |
+
'x-rating' => _fs_text( '%s rating' ),
|
580 |
+
/* translators: %s: Number larger than 1 */
|
581 |
+
'x-ratings' => _fs_text( '%s ratings' ),
|
582 |
+
/* translators: %s: 1 or One (Number of times downloaded) */
|
583 |
+
'x-time' => _fs_text( '%s time' ),
|
584 |
+
/* translators: %s: Number of times downloaded */
|
585 |
+
'x-times' => _fs_text( '%s times' ),
|
586 |
+
/* translators: %s: # of stars (e.g. 5 stars) */
|
587 |
+
'click-to-reviews' => _fs_text( 'Click to see reviews that provided a rating of %s' ),
|
588 |
+
'last-updated:' => _fs_text( 'Last Updated' ),
|
589 |
+
'requires-wordpress-version:' => _fs_text( 'Requires WordPress Version:' ),
|
590 |
+
'author:' => _fs_x( 'Author:', 'as the plugin author' ),
|
591 |
+
'compatible-up-to:' => _fs_text( 'Compatible up to:' ),
|
592 |
+
'downloaded:' => _fs_text( 'Downloaded:' ),
|
593 |
+
'wp-org-plugin-page' => _fs_text( 'WordPress.org Plugin Page' ),
|
594 |
+
'plugin-homepage' => _fs_text( 'Plugin Homepage' ),
|
595 |
+
'donate-to-plugin' => _fs_text( 'Donate to this plugin' ),
|
596 |
+
'average-rating' => _fs_text( 'Average Rating' ),
|
597 |
+
'based-on-x' => _fs_text( 'based on %s' ),
|
598 |
+
'warning:' => _fs_text( 'Warning:' ),
|
599 |
+
'contributors' => _fs_text( 'Contributors' ),
|
600 |
+
'plugin-install' => _fs_text( 'Plugin Install' ),
|
601 |
+
'not-tested-warning' => _fs_text( 'This plugin has not been tested with your current version of WordPress.' ),
|
602 |
+
'not-compatible-warning' => _fs_text( 'This plugin has not been marked as compatible with your version of WordPress.' ),
|
603 |
+
'newer-installed' => _fs_text( 'Newer Version (%s) Installed' ),
|
604 |
+
'latest-installed' => _fs_text( 'Latest Version Installed' ),
|
605 |
+
);
|
freemius/includes/managers/class-fs-plugin-manager.php
CHANGED
@@ -1,220 +1,220 @@
|
|
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 1.0.6
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
class FS_Plugin_Manager {
|
14 |
-
/**
|
15 |
-
* @since 1.2.2
|
16 |
-
*
|
17 |
-
* @var string|number
|
18 |
-
*/
|
19 |
-
protected $_module_id;
|
20 |
-
/**
|
21 |
-
* @since 1.2.2
|
22 |
-
*
|
23 |
-
* @var FS_Plugin
|
24 |
-
*/
|
25 |
-
protected $_module;
|
26 |
-
|
27 |
-
/**
|
28 |
-
* @var FS_Plugin_Manager[]
|
29 |
-
*/
|
30 |
-
private static $_instances = array();
|
31 |
-
/**
|
32 |
-
* @var FS_Logger
|
33 |
-
*/
|
34 |
-
protected $_logger;
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Option names
|
38 |
-
*
|
39 |
-
* @author Leo Fajardo (@leorw)
|
40 |
-
* @since 1.2.2
|
41 |
-
*/
|
42 |
-
const OPTION_NAME_PLUGINS = 'plugins';
|
43 |
-
const OPTION_NAME_THEMES = 'themes';
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @param string|number $module_id
|
47 |
-
*
|
48 |
-
* @return FS_Plugin_Manager
|
49 |
-
*/
|
50 |
-
static function instance( $module_id ) {
|
51 |
-
$key = 'm_' . $module_id;
|
52 |
-
|
53 |
-
if ( ! isset( self::$_instances[ $key ] ) ) {
|
54 |
-
self::$_instances[ $key ] = new FS_Plugin_Manager( $module_id );
|
55 |
-
}
|
56 |
-
|
57 |
-
return self::$_instances[ $key ];
|
58 |
-
}
|
59 |
-
|
60 |
-
/**
|
61 |
-
* @param string|number $module_id
|
62 |
-
*/
|
63 |
-
protected function __construct( $module_id ) {
|
64 |
-
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $module_id . '_' . 'plugins', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
65 |
-
$this->_module_id = $module_id;
|
66 |
-
|
67 |
-
$this->load();
|
68 |
-
}
|
69 |
-
|
70 |
-
protected function get_option_manager() {
|
71 |
-
return FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true, true );
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* @author Leo Fajardo (@leorw)
|
76 |
-
* @since 1.2.2
|
77 |
-
*
|
78 |
-
* @param string|bool $module_type "plugin", "theme", or "false" for all modules.
|
79 |
-
*
|
80 |
-
* @return array
|
81 |
-
*/
|
82 |
-
protected function get_all_modules( $module_type = false ) {
|
83 |
-
$option_manager = $this->get_option_manager();
|
84 |
-
|
85 |
-
if ( false !== $module_type ) {
|
86 |
-
return fs_get_entities( $option_manager->get_option( $module_type . 's', array() ), FS_Plugin::get_class_name() );
|
87 |
-
}
|
88 |
-
|
89 |
-
return array(
|
90 |
-
self::OPTION_NAME_PLUGINS => fs_get_entities( $option_manager->get_option( self::OPTION_NAME_PLUGINS, array() ), FS_Plugin::get_class_name() ),
|
91 |
-
self::OPTION_NAME_THEMES => fs_get_entities( $option_manager->get_option( self::OPTION_NAME_THEMES, array() ), FS_Plugin::get_class_name() ),
|
92 |
-
);
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* Load plugin data from local DB.
|
97 |
-
*
|
98 |
-
* @author Vova Feldman (@svovaf)
|
99 |
-
* @since 1.0.6
|
100 |
-
*/
|
101 |
-
function load() {
|
102 |
-
$all_modules = $this->get_all_modules();
|
103 |
-
|
104 |
-
if ( ! is_numeric( $this->_module_id ) ) {
|
105 |
-
unset( $all_modules[ self::OPTION_NAME_THEMES ] );
|
106 |
-
}
|
107 |
-
|
108 |
-
foreach ( $all_modules as $modules ) {
|
109 |
-
/**
|
110 |
-
* @since 1.2.2
|
111 |
-
*
|
112 |
-
* @var $modules FS_Plugin[]
|
113 |
-
*/
|
114 |
-
foreach ( $modules as $module ) {
|
115 |
-
$found_module = false;
|
116 |
-
|
117 |
-
/**
|
118 |
-
* If module ID is not numeric, it must be a plugin's slug.
|
119 |
-
*
|
120 |
-
* @author Leo Fajardo (@leorw)
|
121 |
-
* @since 1.2.2
|
122 |
-
*/
|
123 |
-
if ( ! is_numeric( $this->_module_id ) ) {
|
124 |
-
if ( $this->_module_id === $module->slug ) {
|
125 |
-
$this->_module_id = $module->id;
|
126 |
-
$found_module = true;
|
127 |
-
}
|
128 |
-
} else if ( $this->_module_id == $module->id ) {
|
129 |
-
$found_module = true;
|
130 |
-
}
|
131 |
-
|
132 |
-
if ( $found_module ) {
|
133 |
-
$this->_module = $module;
|
134 |
-
break;
|
135 |
-
}
|
136 |
-
}
|
137 |
-
}
|
138 |
-
}
|
139 |
-
|
140 |
-
/**
|
141 |
-
* Store plugin on local DB.
|
142 |
-
*
|
143 |
-
* @author Vova Feldman (@svovaf)
|
144 |
-
* @since 1.0.6
|
145 |
-
*
|
146 |
-
* @param bool|FS_Plugin $module
|
147 |
-
* @param bool $flush
|
148 |
-
*
|
149 |
-
* @return bool|\FS_Plugin
|
150 |
-
*/
|
151 |
-
function store( $module = false, $flush = true ) {
|
152 |
-
if ( false !== $module ) {
|
153 |
-
$this->_module = $module;
|
154 |
-
}
|
155 |
-
|
156 |
-
$all_modules = $this->get_all_modules( $this->_module->type );
|
157 |
-
$all_modules[ $this->_module->slug ] = $this->_module;
|
158 |
-
|
159 |
-
$options_manager = $this->get_option_manager();
|
160 |
-
$options_manager->set_option( $this->_module->type . 's', $all_modules, $flush );
|
161 |
-
|
162 |
-
return $this->_module;
|
163 |
-
}
|
164 |
-
|
165 |
-
/**
|
166 |
-
* Update local plugin data if different.
|
167 |
-
*
|
168 |
-
* @author Vova Feldman (@svovaf)
|
169 |
-
* @since 1.0.6
|
170 |
-
*
|
171 |
-
* @param \FS_Plugin $plugin
|
172 |
-
* @param bool $store
|
173 |
-
*
|
174 |
-
* @return bool True if plugin was updated.
|
175 |
-
*/
|
176 |
-
function update( FS_Plugin $plugin, $store = true ) {
|
177 |
-
if ( ! ($this->_module instanceof FS_Plugin ) ||
|
178 |
-
$this->_module->slug != $plugin->slug ||
|
179 |
-
$this->_module->public_key != $plugin->public_key ||
|
180 |
-
$this->_module->secret_key != $plugin->secret_key ||
|
181 |
-
$this->_module->parent_plugin_id != $plugin->parent_plugin_id ||
|
182 |
-
$this->_module->title != $plugin->title
|
183 |
-
) {
|
184 |
-
$this->store( $plugin, $store );
|
185 |
-
|
186 |
-
return true;
|
187 |
-
}
|
188 |
-
|
189 |
-
return false;
|
190 |
-
}
|
191 |
-
|
192 |
-
/**
|
193 |
-
* @author Vova Feldman (@svovaf)
|
194 |
-
* @since 1.0.6
|
195 |
-
*
|
196 |
-
* @param FS_Plugin $plugin
|
197 |
-
* @param bool $store
|
198 |
-
*/
|
199 |
-
function set( FS_Plugin $plugin, $store = false ) {
|
200 |
-
$this->_module = $plugin;
|
201 |
-
|
202 |
-
if ( $store ) {
|
203 |
-
$this->store();
|
204 |
-
}
|
205 |
-
}
|
206 |
-
|
207 |
-
/**
|
208 |
-
* @author Vova Feldman (@svovaf)
|
209 |
-
* @since 1.0.6
|
210 |
-
*
|
211 |
-
* @return bool|\FS_Plugin
|
212 |
-
*/
|
213 |
-
function get() {
|
214 |
-
return isset( $this->_module ) ?
|
215 |
-
$this->_module :
|
216 |
-
false;
|
217 |
-
}
|
218 |
-
|
219 |
-
|
220 |
}
|
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 1.0.6
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
class FS_Plugin_Manager {
|
14 |
+
/**
|
15 |
+
* @since 1.2.2
|
16 |
+
*
|
17 |
+
* @var string|number
|
18 |
+
*/
|
19 |
+
protected $_module_id;
|
20 |
+
/**
|
21 |
+
* @since 1.2.2
|
22 |
+
*
|
23 |
+
* @var FS_Plugin
|
24 |
+
*/
|
25 |
+
protected $_module;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var FS_Plugin_Manager[]
|
29 |
+
*/
|
30 |
+
private static $_instances = array();
|
31 |
+
/**
|
32 |
+
* @var FS_Logger
|
33 |
+
*/
|
34 |
+
protected $_logger;
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Option names
|
38 |
+
*
|
39 |
+
* @author Leo Fajardo (@leorw)
|
40 |
+
* @since 1.2.2
|
41 |
+
*/
|
42 |
+
const OPTION_NAME_PLUGINS = 'plugins';
|
43 |
+
const OPTION_NAME_THEMES = 'themes';
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @param string|number $module_id
|
47 |
+
*
|
48 |
+
* @return FS_Plugin_Manager
|
49 |
+
*/
|
50 |
+
static function instance( $module_id ) {
|
51 |
+
$key = 'm_' . $module_id;
|
52 |
+
|
53 |
+
if ( ! isset( self::$_instances[ $key ] ) ) {
|
54 |
+
self::$_instances[ $key ] = new FS_Plugin_Manager( $module_id );
|
55 |
+
}
|
56 |
+
|
57 |
+
return self::$_instances[ $key ];
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param string|number $module_id
|
62 |
+
*/
|
63 |
+
protected function __construct( $module_id ) {
|
64 |
+
$this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $module_id . '_' . 'plugins', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
|
65 |
+
$this->_module_id = $module_id;
|
66 |
+
|
67 |
+
$this->load();
|
68 |
+
}
|
69 |
+
|
70 |
+
protected function get_option_manager() {
|
71 |
+
return FS_Option_Manager::get_manager( WP_FS__ACCOUNTS_OPTION_NAME, true, true );
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* @author Leo Fajardo (@leorw)
|
76 |
+
* @since 1.2.2
|
77 |
+
*
|
78 |
+
* @param string|bool $module_type "plugin", "theme", or "false" for all modules.
|
79 |
+
*
|
80 |
+
* @return array
|
81 |
+
*/
|
82 |
+
protected function get_all_modules( $module_type = false ) {
|
83 |
+
$option_manager = $this->get_option_manager();
|
84 |
+
|
85 |
+
if ( false !== $module_type ) {
|
86 |
+
return fs_get_entities( $option_manager->get_option( $module_type . 's', array() ), FS_Plugin::get_class_name() );
|
87 |
+
}
|
88 |
+
|
89 |
+
return array(
|
90 |
+
self::OPTION_NAME_PLUGINS => fs_get_entities( $option_manager->get_option( self::OPTION_NAME_PLUGINS, array() ), FS_Plugin::get_class_name() ),
|
91 |
+
self::OPTION_NAME_THEMES => fs_get_entities( $option_manager->get_option( self::OPTION_NAME_THEMES, array() ), FS_Plugin::get_class_name() ),
|
92 |
+
);
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Load plugin data from local DB.
|
97 |
+
*
|
98 |
+
* @author Vova Feldman (@svovaf)
|
99 |
+
* @since 1.0.6
|
100 |
+
*/
|
101 |
+
function load() {
|
102 |
+
$all_modules = $this->get_all_modules();
|
103 |
+
|
104 |
+
if ( ! is_numeric( $this->_module_id ) ) {
|
105 |
+
unset( $all_modules[ self::OPTION_NAME_THEMES ] );
|
106 |
+
}
|
107 |
+
|
108 |
+
foreach ( $all_modules as $modules ) {
|
109 |
+
/**
|
110 |
+
* @since 1.2.2
|
111 |
+
*
|
112 |
+
* @var $modules FS_Plugin[]
|
113 |
+
*/
|
114 |
+
foreach ( $modules as $module ) {
|
115 |
+
$found_module = false;
|
116 |
+
|
117 |
+
/**
|
118 |
+
* If module ID is not numeric, it must be a plugin's slug.
|
119 |
+
*
|
120 |
+
* @author Leo Fajardo (@leorw)
|
121 |
+
* @since 1.2.2
|
122 |
+
*/
|
123 |
+
if ( ! is_numeric( $this->_module_id ) ) {
|
124 |
+
if ( $this->_module_id === $module->slug ) {
|
125 |
+
$this->_module_id = $module->id;
|
126 |
+
$found_module = true;
|
127 |
+
}
|
128 |
+
} else if ( $this->_module_id == $module->id ) {
|
129 |
+
$found_module = true;
|
130 |
+
}
|
131 |
+
|
132 |
+
if ( $found_module ) {
|
133 |
+
$this->_module = $module;
|
134 |
+
break;
|
135 |
+
}
|
136 |
+
}
|
137 |
+
}
|
138 |
+
}
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Store plugin on local DB.
|
142 |
+
*
|
143 |
+
* @author Vova Feldman (@svovaf)
|
144 |
+
* @since 1.0.6
|
145 |
+
*
|
146 |
+
* @param bool|FS_Plugin $module
|
147 |
+
* @param bool $flush
|
148 |
+
*
|
149 |
+
* @return bool|\FS_Plugin
|
150 |
+
*/
|
151 |
+
function store( $module = false, $flush = true ) {
|
152 |
+
if ( false !== $module ) {
|
153 |
+
$this->_module = $module;
|
154 |
+
}
|
155 |
+
|
156 |
+
$all_modules = $this->get_all_modules( $this->_module->type );
|
157 |
+
$all_modules[ $this->_module->slug ] = $this->_module;
|
158 |
+
|
159 |
+
$options_manager = $this->get_option_manager();
|
160 |
+
$options_manager->set_option( $this->_module->type . 's', $all_modules, $flush );
|
161 |
+
|
162 |
+
return $this->_module;
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Update local plugin data if different.
|
167 |
+
*
|
168 |
+
* @author Vova Feldman (@svovaf)
|
169 |
+
* @since 1.0.6
|
170 |
+
*
|
171 |
+
* @param \FS_Plugin $plugin
|
172 |
+
* @param bool $store
|
173 |
+
*
|
174 |
+
* @return bool True if plugin was updated.
|
175 |
+
*/
|
176 |
+
function update( FS_Plugin $plugin, $store = true ) {
|
177 |
+
if ( ! ($this->_module instanceof FS_Plugin ) ||
|
178 |
+
$this->_module->slug != $plugin->slug ||
|
179 |
+
$this->_module->public_key != $plugin->public_key ||
|
180 |
+
$this->_module->secret_key != $plugin->secret_key ||
|
181 |
+
$this->_module->parent_plugin_id != $plugin->parent_plugin_id ||
|
182 |
+
$this->_module->title != $plugin->title
|
183 |
+
) {
|
184 |
+
$this->store( $plugin, $store );
|
185 |
+
|
186 |
+
return true;
|
187 |
+
}
|
188 |
+
|
189 |
+
return false;
|
190 |
+
}
|
191 |
+
|
192 |
+
/**
|
193 |
+
* @author Vova Feldman (@svovaf)
|
194 |
+
* @since 1.0.6
|
195 |
+
*
|
196 |
+
* @param FS_Plugin $plugin
|
197 |
+
* @param bool $store
|
198 |
+
*/
|
199 |
+
function set( FS_Plugin $plugin, $store = false ) {
|
200 |
+
$this->_module = $plugin;
|
201 |
+
|
202 |
+
if ( $store ) {
|
203 |
+
$this->store();
|
204 |
+
}
|
205 |
+
}
|
206 |
+
|
207 |
+
/**
|
208 |
+
* @author Vova Feldman (@svovaf)
|
209 |
+
* @since 1.0.6
|
210 |
+
*
|
211 |
+
* @return bool|\FS_Plugin
|
212 |
+
*/
|
213 |
+
function get() {
|
214 |
+
return isset( $this->_module ) ?
|
215 |
+
$this->_module :
|
216 |
+
false;
|
217 |
+
}
|
218 |
+
|
219 |
+
|
220 |
}
|
freemius/templates/account.php
CHANGED
@@ -1,1098 +1,1098 @@
|
|
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 1.0.3
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
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 |
-
/**
|
22 |
-
* @var FS_Plugin_Tag $update
|
23 |
-
*/
|
24 |
-
$update = $fs->has_release_on_freemius() ?
|
25 |
-
$fs->get_update( false, false, WP_FS__TIME_24_HOURS_IN_SEC / 24 ) :
|
26 |
-
null;
|
27 |
-
|
28 |
-
if ( is_object($update) ) {
|
29 |
-
/**
|
30 |
-
* This logic is particularly required for multisite environment.
|
31 |
-
* If a module is site activated (not network) and not on the main site,
|
32 |
-
* the module will NOT be executed on the network level, therefore, the
|
33 |
-
* custom updates logic will not be executed as well, so unless we force
|
34 |
-
* the injection of the update into the updates transient, premium updates
|
35 |
-
* will not work.
|
36 |
-
*
|
37 |
-
* @author Vova Feldman (@svovaf)
|
38 |
-
* @since 2.0.0
|
39 |
-
*/
|
40 |
-
$updater = FS_Plugin_Updater::instance( $fs );
|
41 |
-
$updater->set_update_data( $update );
|
42 |
-
}
|
43 |
-
|
44 |
-
$is_paying = $fs->is_paying();
|
45 |
-
$user = $fs->get_user();
|
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 ) ?
|
52 |
-
$fs->_get_subscription( $license->id ) :
|
53 |
-
null );
|
54 |
-
$plan = $fs->get_plan();
|
55 |
-
$is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
|
56 |
-
$is_paid_trial = $fs->is_paid_trial();
|
57 |
-
$has_paid_plan = $fs->apply_filters( 'has_paid_plan_account', $fs->has_paid_plan() );
|
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();
|
68 |
-
|
69 |
-
if ( ! empty( $ids_of_installs_activated_with_foreign_licenses ) ) {
|
70 |
-
$fs->_add_user_change_dialog_box( $ids_of_installs_activated_with_foreign_licenses );
|
71 |
-
}
|
72 |
-
|
73 |
-
if ( $fs->is_whitelabeled( true ) || $fs->is_data_debug_mode() ) {
|
74 |
-
$fs->_add_data_debug_mode_dialog_box();
|
75 |
-
}
|
76 |
-
|
77 |
-
if ( fs_request_get_bool( 'auto_install' ) ) {
|
78 |
-
$fs->_add_auto_installation_dialog_box();
|
79 |
-
}
|
80 |
-
|
81 |
-
if ( fs_request_get_bool( 'activate_license' ) ) {
|
82 |
-
// Open the license activation dialog box on the account page.
|
83 |
-
add_action( 'admin_footer', array(
|
84 |
-
&$fs,
|
85 |
-
'_open_license_activation_dialog_box'
|
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';
|
98 |
-
}
|
99 |
-
|
100 |
-
// Aliases.
|
101 |
-
$download_latest_text = fs_text_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $slug );
|
102 |
-
$downgrading_plan_text = fs_text_inline( 'Downgrading your plan', 'downgrading-plan', $slug );
|
103 |
-
$cancelling_subscription_text = fs_text_inline( 'Cancelling the subscription', 'cancelling-subscription', $slug );
|
104 |
-
/* translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription' */
|
105 |
-
$downgrade_x_confirm_text = fs_text_inline( '%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s.', 'downgrade-x-confirm', $slug );
|
106 |
-
$prices_increase_text = fs_text_inline( '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.', 'pricing-increase-warning', $slug );
|
107 |
-
$cancel_trial_confirm_text = fs_text_inline( 'Cancelling the trial will immediately block access to all premium features. Are you sure?', 'cancel-trial-confirm', $slug );
|
108 |
-
$after_downgrade_non_blocking_text = fs_text_inline( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.', 'after-downgrade-non-blocking', $slug );
|
109 |
-
$after_downgrade_blocking_text = fs_text_inline( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.', 'after-downgrade-blocking', $slug );
|
110 |
-
/* translators: %s: Plan title (e.g. "Professional") */
|
111 |
-
$activate_plan_text = fs_text_inline( 'Activate %s Plan', 'activate-x-plan', $slug );
|
112 |
-
$version_text = fs_text_x_inline( 'Version', 'product version', 'version', $slug );
|
113 |
-
/* translators: %s: Time period (e.g. Auto renews in "2 months") */
|
114 |
-
$renews_in_text = fs_text_inline( 'Auto renews in %s', 'renews-in', $slug );
|
115 |
-
/* translators: %s: Time period (e.g. Expires in "2 months") */
|
116 |
-
$expires_in_text = fs_text_inline( 'Expires in %s', 'expires-in', $slug );
|
117 |
-
$sync_license_text = fs_text_x_inline( 'Sync License', 'as synchronize license', 'sync-license', $slug );
|
118 |
-
$cancel_trial_text = fs_text_inline( 'Cancel Trial', 'cancel-trial', $slug );
|
119 |
-
$change_plan_text = fs_text_inline( 'Change Plan', 'change-plan', $slug );
|
120 |
-
$upgrade_text = fs_text_x_inline( 'Upgrade', 'verb', 'upgrade', $slug );
|
121 |
-
$addons_text = fs_text_inline( 'Add-Ons', 'add-ons', $slug );
|
122 |
-
$downgrade_text = fs_text_x_inline( 'Downgrade', 'verb', 'downgrade', $slug );
|
123 |
-
$trial_text = fs_text_x_inline( 'Trial', 'trial period', 'trial', $slug );
|
124 |
-
$free_text = fs_text_inline( 'Free', 'free', $slug );
|
125 |
-
$activate_text = fs_text_inline( 'Activate', 'activate', $slug );
|
126 |
-
$plan_text = fs_text_x_inline( 'Plan', 'as product pricing plan', 'plan', $slug );
|
127 |
-
$bundle_plan_text = fs_text_inline( 'Bundle Plan', 'bundle-plan', $slug );
|
128 |
-
|
129 |
-
$show_plan_row = true;
|
130 |
-
$show_license_row = is_object( $license );
|
131 |
-
|
132 |
-
$site_view_params = array();
|
133 |
-
|
134 |
-
if ( fs_is_network_admin() ) {
|
135 |
-
$sites = Freemius::get_sites();
|
136 |
-
$all_installs_plan_id = null;
|
137 |
-
$all_installs_license_id = ( $show_license_row ? $license->id : null );
|
138 |
-
foreach ( $sites as $s ) {
|
139 |
-
$site_info = $fs->get_site_info( $s );
|
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,
|
146 |
-
);
|
147 |
-
|
148 |
-
$site_view_params[] = $view_params;
|
149 |
-
|
150 |
-
if ( empty( $install ) ) {
|
151 |
-
continue;
|
152 |
-
}
|
153 |
-
|
154 |
-
if ( $show_plan_row ) {
|
155 |
-
if ( is_null( $all_installs_plan_id ) ) {
|
156 |
-
$all_installs_plan_id = $install->plan_id;
|
157 |
-
} else if ( $all_installs_plan_id != $install->plan_id ) {
|
158 |
-
$show_plan_row = false;
|
159 |
-
}
|
160 |
-
}
|
161 |
-
|
162 |
-
if ( $show_license_row && $all_installs_license_id != $install->license_id ) {
|
163 |
-
$show_license_row = false;
|
164 |
-
}
|
165 |
-
}
|
166 |
-
}
|
167 |
-
|
168 |
-
$has_bundle_license = false;
|
169 |
-
|
170 |
-
if ( is_object( $license ) &&
|
171 |
-
FS_Plugin_License::is_valid_id( $license->parent_license_id )
|
172 |
-
) {
|
173 |
-
// Context license has a parent license, therefore, the account has a bundle license.
|
174 |
-
$has_bundle_license = true;
|
175 |
-
}
|
176 |
-
|
177 |
-
$bundle_subscription = null;
|
178 |
-
$is_bundle_first_payment_pending = false;
|
179 |
-
|
180 |
-
if (
|
181 |
-
$show_plan_row &&
|
182 |
-
is_object( $license ) &&
|
183 |
-
$has_bundle_license
|
184 |
-
) {
|
185 |
-
$bundle_plan_title = strtoupper( $license->parent_plan_title );
|
186 |
-
$bundle_subscription = $fs->_get_subscription( $license->parent_license_id );
|
187 |
-
$is_bundle_first_payment_pending = $license->is_first_payment_pending();
|
188 |
-
}
|
189 |
-
|
190 |
-
$fs_blog_id = ( is_multisite() && ! is_network_admin() ) ?
|
191 |
-
get_current_blog_id() :
|
192 |
-
0;
|
193 |
-
|
194 |
-
$active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $fs_blog_id );
|
195 |
-
|
196 |
-
$is_premium = $fs->is_premium();
|
197 |
-
|
198 |
-
$account_addons = $fs->get_updated_account_addons();
|
199 |
-
$installed_addons = $fs->get_installed_addons();
|
200 |
-
$installed_addons_ids = array();
|
201 |
-
|
202 |
-
/**
|
203 |
-
* Store the installed add-ons' IDs into a collection which will be used in determining the add-ons to show on the "Account" page, and at the same time try to find an add-on that is activated with a bundle license if the core product is not.
|
204 |
-
*
|
205 |
-
* @author Leo Fajardo
|
206 |
-
*
|
207 |
-
* @since 2.4.0
|
208 |
-
*/
|
209 |
-
foreach ( $installed_addons as $fs_addon ) {
|
210 |
-
$installed_addons_ids[] = $fs_addon->get_id();
|
211 |
-
|
212 |
-
if ( $has_bundle_license ) {
|
213 |
-
// We already have the context bundle license details, skip.
|
214 |
-
continue;
|
215 |
-
}
|
216 |
-
|
217 |
-
if (
|
218 |
-
$show_plan_row &&
|
219 |
-
$fs_addon->has_active_valid_license()
|
220 |
-
) {
|
221 |
-
$addon_license = $fs_addon->_get_license();
|
222 |
-
|
223 |
-
if ( FS_Plugin_License::is_valid_id( $addon_license->parent_license_id ) ) {
|
224 |
-
// Add-on's license is associated with a parent/bundle license.
|
225 |
-
$has_bundle_license = true;
|
226 |
-
|
227 |
-
$bundle_plan_title = strtoupper( $addon_license->parent_plan_title );
|
228 |
-
$bundle_subscription = $fs_addon->_get_subscription( $addon_license->parent_license_id );
|
229 |
-
$is_bundle_first_payment_pending = $addon_license->is_first_payment_pending();
|
230 |
-
}
|
231 |
-
}
|
232 |
-
}
|
233 |
-
|
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 ) ) : ?>
|
240 |
-
<h2 class="nav-tab-wrapper">
|
241 |
-
<a href="<?php echo $fs->get_account_url() ?>"
|
242 |
-
class="nav-tab nav-tab-active"><?php fs_esc_html_echo_inline( 'Account', 'account', $slug ) ?></a>
|
243 |
-
<?php if ( $fs->has_addons() ) : ?>
|
244 |
-
<a href="<?php echo $fs->_get_admin_page_url( 'addons' ) ?>"
|
245 |
-
class="nav-tab"><?php echo esc_html( $addons_text ) ?></a>
|
246 |
-
<?php endif ?>
|
247 |
-
<?php if ( $show_upgrade ) : ?>
|
248 |
-
<a href="<?php echo $fs->get_upgrade_url() ?>" class="nav-tab"><?php echo esc_html( $upgrade_text ) ?></a>
|
249 |
-
<?php if ( $fs->apply_filters( 'show_trial', true ) && ! $fs->is_trial_utilized() && $fs->has_trial_plan() ) : ?>
|
250 |
-
<a href="<?php echo $fs->get_trial_url() ?>" class="nav-tab"><?php fs_esc_html_echo_inline( 'Free Trial', 'free-trial', $slug ) ?></a>
|
251 |
-
<?php endif ?>
|
252 |
-
<?php endif ?>
|
253 |
-
</h2>
|
254 |
-
<?php endif ?>
|
255 |
-
|
256 |
-
<div id="poststuff">
|
257 |
-
<div id="fs_account">
|
258 |
-
<div class="has-sidebar has-right-sidebar">
|
259 |
-
<div class="has-sidebar-content">
|
260 |
-
<div class="postbox">
|
261 |
-
<h3><span class="dashicons dashicons-businessman"></span> <?php fs_esc_html_echo_inline( 'Account Details', 'account-details', $slug ) ?></h3>
|
262 |
-
<div class="fs-header-actions">
|
263 |
-
<ul>
|
264 |
-
<?php if ( $fs->is_whitelabeled( true ) ) : ?>
|
265 |
-
<li>
|
266 |
-
<a href="#" class="debug-license-trigger"><i class="dashicons dashicons-<?php echo $is_whitelabeled ? 'editor-code' : 'controls-pause' ?>"></i> <span><?php
|
267 |
-
if ( $is_whitelabeled ) {
|
268 |
-
fs_esc_html_echo_inline( 'Start Debug', 'start-debug-license', $slug );
|
269 |
-
} else {
|
270 |
-
fs_esc_html_echo_inline( 'Stop Debug', 'stop-debug-license', $slug );
|
271 |
-
}
|
272 |
-
?></span></a>
|
273 |
-
</li>
|
274 |
-
<li> • </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> • </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> • </li>
|
297 |
-
<?php endif ?>
|
298 |
-
<?php if ( $is_paying ) : ?>
|
299 |
-
<?php if ( ! fs_is_network_admin() ) : ?>
|
300 |
-
<li>
|
301 |
-
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
302 |
-
<input type="hidden" name="fs_action" value="deactivate_license">
|
303 |
-
<?php wp_nonce_field( 'deactivate_license' ) ?>
|
304 |
-
<a href="#" class="fs-deactivate-license"><i
|
305 |
-
class="dashicons dashicons-admin-network"></i> <?php fs_echo_inline( 'Deactivate License', 'deactivate-license', $slug ) ?>
|
306 |
-
</a>
|
307 |
-
</form>
|
308 |
-
</li>
|
309 |
-
<li> • </li>
|
310 |
-
<?php endif ?>
|
311 |
-
<?php if ( ! $license->is_lifetime() &&
|
312 |
-
$is_active_subscription
|
313 |
-
) : ?>
|
314 |
-
<li>
|
315 |
-
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
316 |
-
<input type="hidden" name="fs_action" value="downgrade_account">
|
317 |
-
<?php wp_nonce_field( 'downgrade_account' ) ?>
|
318 |
-
<a href="#"
|
319 |
-
onclick="if ( confirm('<?php echo esc_attr( sprintf(
|
320 |
-
$downgrade_x_confirm_text,
|
321 |
-
( $fs->is_only_premium() ? $cancelling_subscription_text : $downgrading_plan_text ),
|
322 |
-
$plan->title,
|
323 |
-
human_time_diff( time(), strtotime( $license->expiration ) )
|
324 |
-
) ) ?> <?php if ( ! $license->is_block_features ) {
|
325 |
-
echo esc_attr( sprintf( $after_downgrade_non_blocking_text, $plan->title, $fs->get_module_label( true ) ) );
|
326 |
-
} else {
|
327 |
-
echo esc_attr( sprintf( $after_downgrade_blocking_text, $plan->title ) );
|
328 |
-
}?> <?php echo esc_attr( $prices_increase_text ) ?> <?php fs_esc_attr_echo_inline( 'Are you sure you want to proceed?', 'proceed-confirmation', $slug ) ?>') ) this.parentNode.submit(); return false;"><i class="dashicons dashicons-download"></i> <?php echo esc_html( $fs->is_only_premium() ? fs_text_inline( 'Cancel Subscription', 'cancel-subscription', $slug ) : $downgrade_text ) ?></a>
|
329 |
-
</form>
|
330 |
-
</li>
|
331 |
-
<li> • </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>
|
337 |
-
</li>
|
338 |
-
<li> • </li>
|
339 |
-
<?php endif ?>
|
340 |
-
<?php elseif ( $is_paid_trial ) : ?>
|
341 |
-
<li>
|
342 |
-
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
343 |
-
<input type="hidden" name="fs_action" value="cancel_trial">
|
344 |
-
<?php wp_nonce_field( 'cancel_trial' ) ?>
|
345 |
-
<a href="#" class="fs-cancel-trial"><i
|
346 |
-
class="dashicons dashicons-download"></i> <?php echo esc_html( $cancel_trial_text ) ?></a>
|
347 |
-
</form>
|
348 |
-
</li>
|
349 |
-
<li> • </li>
|
350 |
-
<?php endif ?>
|
351 |
-
<?php endif ?>
|
352 |
-
<li>
|
353 |
-
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
354 |
-
<input type="hidden" name="fs_action" value="<?php echo $fs->get_unique_affix() ?>_sync_license">
|
355 |
-
<?php wp_nonce_field( $fs->get_unique_affix() . '_sync_license' ) ?>
|
356 |
-
<a href="#" onclick="this.parentNode.submit(); return false;"><i
|
357 |
-
class="dashicons dashicons-image-rotate"></i> <?php fs_esc_html_echo_x_inline( 'Sync', 'as synchronize', 'sync', $slug ) ?></a>
|
358 |
-
</form>
|
359 |
-
</li>
|
360 |
-
</ul>
|
361 |
-
</div>
|
362 |
-
<div class="inside">
|
363 |
-
<table id="fs_account_details" cellspacing="0" class="fs-key-value-table">
|
364 |
-
<?php
|
365 |
-
$hide_license_key = ( ! $show_license_row || $fs->apply_filters( 'hide_license_key', false ) );
|
366 |
-
|
367 |
-
$profile = array();
|
368 |
-
|
369 |
-
if ( ! $is_whitelabeled ) {
|
370 |
-
$profile[] = array(
|
371 |
-
'id' => 'user_name',
|
372 |
-
'title' => fs_text_inline( 'Name', 'name', $slug ),
|
373 |
-
'value' => $name
|
374 |
-
);
|
375 |
-
// if (isset($user->email) && false !== strpos($user->email, '@'))
|
376 |
-
$profile[] = array(
|
377 |
-
'id' => 'email',
|
378 |
-
'title' => fs_text_inline( 'Email', 'email', $slug ),
|
379 |
-
'value' => $user->email
|
380 |
-
);
|
381 |
-
|
382 |
-
if ( is_numeric( $user->id ) ) {
|
383 |
-
$profile[] = array(
|
384 |
-
'id' => 'user_id',
|
385 |
-
'title' => fs_text_inline( 'User ID', 'user-id', $slug ),
|
386 |
-
'value' => $user->id
|
387 |
-
);
|
388 |
-
}
|
389 |
-
}
|
390 |
-
|
391 |
-
$profile[] = array(
|
392 |
-
'id' => 'product',
|
393 |
-
'title' => ( $fs->is_plugin() ?
|
394 |
-
fs_text_inline( 'Plugin', 'plugin', $slug ) :
|
395 |
-
fs_text_inline( 'Theme', 'theme', $slug ) ),
|
396 |
-
'value' => $fs->get_plugin_title()
|
397 |
-
);
|
398 |
-
|
399 |
-
$profile[] = array(
|
400 |
-
'id' => 'product_id',
|
401 |
-
'title' => ( $fs->is_plugin() ?
|
402 |
-
fs_text_inline( 'Plugin', 'plugin', $slug ) :
|
403 |
-
fs_text_inline( 'Theme', 'theme', $slug ) ) . ' ' . fs_text_inline( 'ID', 'id', $slug ),
|
404 |
-
'value' => $fs->get_id()
|
405 |
-
);
|
406 |
-
|
407 |
-
if ( ! fs_is_network_admin()) {
|
408 |
-
$profile[] = array(
|
409 |
-
'id' => 'site_id',
|
410 |
-
'title' => fs_text_inline( 'Site ID', 'site-id', $slug ),
|
411 |
-
'value' => is_string( $site->id ) ?
|
412 |
-
$site->id :
|
413 |
-
fs_text_inline( 'No ID', 'no-id', $slug )
|
414 |
-
);
|
415 |
-
|
416 |
-
$profile[] = array(
|
417 |
-
'id' => 'site_public_key',
|
418 |
-
'title' => fs_text_inline( 'Public Key', 'public-key', $slug ),
|
419 |
-
'value' => $site->public_key
|
420 |
-
);
|
421 |
-
|
422 |
-
$profile[] = array(
|
423 |
-
'id' => 'site_secret_key',
|
424 |
-
'title' => fs_text_inline( 'Secret Key', 'secret-key', $slug ),
|
425 |
-
'value' => ( ( is_string( $site->secret_key ) ) ?
|
426 |
-
$site->secret_key :
|
427 |
-
fs_text_x_inline( 'No Secret', 'as secret encryption key missing', 'no-secret', $slug )
|
428 |
-
)
|
429 |
-
);
|
430 |
-
}
|
431 |
-
|
432 |
-
$profile[] = array(
|
433 |
-
'id' => 'version',
|
434 |
-
'title' => $version_text,
|
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' => '',
|
442 |
-
'value' => $site->is_beta
|
443 |
-
);
|
444 |
-
}
|
445 |
-
|
446 |
-
if ( $has_paid_plan || $has_bundle_license ) {
|
447 |
-
if ( $fs->is_trial() ) {
|
448 |
-
if ( $show_plan_row ) {
|
449 |
-
$profile[] = array(
|
450 |
-
'id' => 'plan',
|
451 |
-
'title' => $plan_text,
|
452 |
-
'value' => ( is_string( $trial_plan->name ) ?
|
453 |
-
strtoupper( $trial_plan->title ) :
|
454 |
-
fs_text_inline( 'Trial', 'trial', $slug ) )
|
455 |
-
);
|
456 |
-
}
|
457 |
-
} else {
|
458 |
-
if ( $show_plan_row ) {
|
459 |
-
$profile[] = array(
|
460 |
-
'id' => 'plan',
|
461 |
-
'title' => ( $has_bundle_license ? ucfirst( $fs->get_module_type() ) . ' ' : '' ) . $plan_text,
|
462 |
-
'value' => strtoupper( is_string( $plan->name ) ?
|
463 |
-
$plan->title :
|
464 |
-
strtoupper( $free_text )
|
465 |
-
)
|
466 |
-
);
|
467 |
-
|
468 |
-
if ( $has_bundle_license ) {
|
469 |
-
$profile[] = array(
|
470 |
-
'id' => 'bundle_plan',
|
471 |
-
'title' => $bundle_plan_text,
|
472 |
-
'value' => $bundle_plan_title
|
473 |
-
);
|
474 |
-
}
|
475 |
-
}
|
476 |
-
|
477 |
-
if ( is_object( $license ) ) {
|
478 |
-
if ( ! $hide_license_key ) {
|
479 |
-
$profile[] = array(
|
480 |
-
'id' => 'license_key',
|
481 |
-
'title' => fs_text_inline( 'License Key', $slug ),
|
482 |
-
'value' => $license->secret_key,
|
483 |
-
);
|
484 |
-
}
|
485 |
-
}
|
486 |
-
}
|
487 |
-
}
|
488 |
-
?>
|
489 |
-
<?php $odd = true;
|
490 |
-
foreach ( $profile as $p ) : ?>
|
491 |
-
<?php
|
492 |
-
if ( 'plan' === $p['id'] && ! $has_paid_plan ) {
|
493 |
-
// If plugin don't have any paid plans, there's no reason
|
494 |
-
// to show current plan.
|
495 |
-
continue;
|
496 |
-
}
|
497 |
-
?>
|
498 |
-
<tr class="fs-field-<?php echo $p['id'] ?><?php if ( $odd ) : ?> alternate<?php endif ?>">
|
499 |
-
<td>
|
500 |
-
<nobr><?php echo $p['title'] ?><?php echo ( ! empty( $p['title'] ) ) ? ':' : '' ?></nobr>
|
501 |
-
</td>
|
502 |
-
<td<?php if ( 'plan' === $p['id'] || 'bundle_plan' === $p['id'] ) { echo ' colspan="2"'; }?>>
|
503 |
-
<?php if ( in_array( $p['id'], array( 'license_key', 'site_secret_key' ) ) ) : ?>
|
504 |
-
<code><?php echo FS_Plugin_License::mask_secret_key_for_html( $p['value'] ) ?></code>
|
505 |
-
<?php if ( ! $is_whitelabeled ) : ?>
|
506 |
-
<input type="text" value="<?php echo htmlspecialchars( $p['value'] ) ?>" style="display: none"
|
507 |
-
readonly/>
|
508 |
-
<?php endif ?>
|
509 |
-
<?php elseif ( 'beta_program' === $p['id'] ) : ?>
|
510 |
-
<label>
|
511 |
-
<input type="checkbox" class="fs-toggle-beta-mode" <?php checked( true, $p['value'] ) ?>/><span><?php
|
512 |
-
fs_esc_html_echo_inline( 'Join the Beta program', 'join-beta', $slug )
|
513 |
-
?></span></label>
|
514 |
-
<?php else : ?>
|
515 |
-
<code><?php echo htmlspecialchars( $p['value'] ) ?></code>
|
516 |
-
<?php endif ?>
|
517 |
-
<?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
|
518 |
-
<label class="fs-tag fs-warn"><?php fs_esc_html_echo_inline( 'not verified', 'not-verified', $slug ) ?></label>
|
519 |
-
<?php endif ?>
|
520 |
-
<?php if ( 'plan' === $p['id'] ) : ?>
|
521 |
-
<?php if ( $fs->is_trial() ) : ?>
|
522 |
-
<label class="fs-tag fs-success"><?php echo esc_html( $trial_text ) ?></label>
|
523 |
-
<?php endif ?>
|
524 |
-
<?php if ( is_object( $license ) && ! $license->is_lifetime() ) : ?>
|
525 |
-
<?php if ( ! $is_active_subscription && ! $is_active_bundle_subscription && ! $license->is_first_payment_pending() ) : ?>
|
526 |
-
<?php $is_license_expired = $license->is_expired() ?>
|
527 |
-
<?php $expired_ago_text = ( fs_text_inline( 'Expired', 'expired', $slug ) . ' ' . fs_text_x_inline( '%s ago', 'x-ago', $slug ) ) ?>
|
528 |
-
<label
|
529 |
-
class="fs-tag <?php echo $is_license_expired ? 'fs-error' : 'fs-warn' ?>"><?php
|
530 |
-
echo esc_html( sprintf( $is_license_expired ? $expired_ago_text : $expires_in_text, human_time_diff( time(), strtotime( $license->expiration ) ) ) )
|
531 |
-
?></label>
|
532 |
-
<?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
|
533 |
-
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ) ?></label>
|
534 |
-
<?php endif ?>
|
535 |
-
<?php elseif ( $fs->is_trial() ) : ?>
|
536 |
-
<label class="fs-tag fs-warn"><?php echo esc_html( sprintf( $expires_in_text, human_time_diff( time(), strtotime( $site->trial_ends ) ) ) ) ?></label>
|
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',
|
552 |
-
);
|
553 |
-
fs_require_template( 'account/partials/activate-license-button.php', $view_params ); ?>
|
554 |
-
<?php else : ?>
|
555 |
-
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
|
556 |
-
method="POST" class="button-group">
|
557 |
-
<?php if ( $show_upgrade && $is_premium ) : ?>
|
558 |
-
<a class="button activate-license-trigger <?php echo $fs->get_unique_affix() ?>" href="#"><?php fs_esc_html_echo_inline( 'Activate License', 'activate-license', $slug ) ?></a>
|
559 |
-
<?php endif ?>
|
560 |
-
<input type="submit" class="button"
|
561 |
-
value="<?php echo esc_attr( $sync_license_text ) ?>">
|
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 ?
|
569 |
-
' button-primary fs-upgrade' :
|
570 |
-
' fs-change-plan'; ?> button-upgrade"><i
|
571 |
-
class="dashicons dashicons-cart"></i> <?php echo esc_html( $show_upgrade ? $upgrade_text : $change_plan_text ) ?></a>
|
572 |
-
<?php endif ?>
|
573 |
-
</form>
|
574 |
-
<?php endif ?>
|
575 |
-
</div>
|
576 |
-
<?php endif ?>
|
577 |
-
<?php elseif ( 'bundle_plan' === $p['id'] ) : ?>
|
578 |
-
<?php if ( is_object( $bundle_subscription ) ) : ?>
|
579 |
-
<?php if ( $is_active_bundle_subscription && ! $is_bundle_first_payment_pending ) : ?>
|
580 |
-
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $bundle_subscription->next_payment ) ) ) ) ?></label>
|
581 |
-
<?php endif ?>
|
582 |
-
<?php endif ?>
|
583 |
-
<?php elseif ( 'version' === $p['id'] && $has_paid_plan ) : ?>
|
584 |
-
<?php if ( $fs->has_premium_version() ) : ?>
|
585 |
-
<?php if ( $is_premium ) : ?>
|
586 |
-
<label
|
587 |
-
class="fs-tag fs-<?php echo $fs->can_use_premium_code() ? 'success' : 'warn' ?>"><?php fs_esc_html_echo_inline( 'Premium version', 'premium-version', $slug ) ?></label>
|
588 |
-
<?php elseif ( $fs->can_use_premium_code() ) : ?>
|
589 |
-
<label class="fs-tag fs-warn"><?php fs_esc_html_echo_inline( 'Free version', 'free-version', $slug ) ?></label>
|
590 |
-
<?php endif ?>
|
591 |
-
<?php endif ?>
|
592 |
-
<?php endif ?>
|
593 |
-
</td>
|
594 |
-
<?php if ( 'plan' !== $p['id'] && 'bundle_plan' !== $p['id'] ) : ?>
|
595 |
-
<td class="fs-right">
|
596 |
-
<?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
|
597 |
-
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
598 |
-
<input type="hidden" name="fs_action" value="verify_email">
|
599 |
-
<?php wp_nonce_field( 'verify_email' ) ?>
|
600 |
-
<input type="submit" class="button button-small"
|
601 |
-
value="<?php fs_esc_attr_echo_inline( 'Verify Email', 'verify-email', $slug ) ?>">
|
602 |
-
</form>
|
603 |
-
<?php endif ?>
|
604 |
-
<?php if ( 'version' === $p['id'] ) : ?>
|
605 |
-
<?php if ( $fs->has_release_on_freemius() ) : ?>
|
606 |
-
<div class="button-group">
|
607 |
-
<?php if ( $is_paying || $fs->is_trial() ) : ?>
|
608 |
-
<?php if ( ! $fs->is_allowed_to_install() ) : ?>
|
609 |
-
<a target="_blank" rel="noopener" class="button button-primary"
|
610 |
-
href="<?php echo $fs->_get_latest_download_local_url() ?>"><?php
|
611 |
-
$download_version_text_suffix = ( is_object( $update ) ? ' [' . $update->version . ']' : '' );
|
612 |
-
|
613 |
-
$download_version_text = sprintf(
|
614 |
-
/* translators: %s: plan name (e.g. Download "Professional" Version) */
|
615 |
-
fs_text_inline( 'Download %s Version', 'download-x-version', $slug ),
|
616 |
-
( $fs->is_trial() ? $trial_plan->title : $plan->title )
|
617 |
-
) .
|
618 |
-
$download_version_text_suffix;
|
619 |
-
|
620 |
-
$download_version_text_length = function_exists( 'mb_strlen' ) ?
|
621 |
-
mb_strlen( $download_version_text ) :
|
622 |
-
strlen( $download_version_text );
|
623 |
-
|
624 |
-
if ( $download_version_text_length > 31 ) {
|
625 |
-
/**
|
626 |
-
* Try to limit the number of characters to 31 for now.
|
627 |
-
*
|
628 |
-
* @author Leo Fajardo (@leorw)
|
629 |
-
* @aince 2.3.2
|
630 |
-
*/
|
631 |
-
$download_version_text = fs_text_inline( 'Download Paid Version', 'download-paid-version', $slug ) . $download_version_text_suffix;
|
632 |
-
}
|
633 |
-
|
634 |
-
echo $download_version_text;
|
635 |
-
?></a>
|
636 |
-
<?php elseif ( is_object( $update ) ) : ?>
|
637 |
-
<?php
|
638 |
-
$module_type = $fs->get_module_type();
|
639 |
-
?>
|
640 |
-
<a class="button button-primary"
|
641 |
-
href="<?php echo wp_nonce_url( self_admin_url( "update.php?action=upgrade-{$module_type}&{$module_type}=" . $fs->get_plugin_basename() ), "upgrade-{$module_type}_" . $fs->get_plugin_basename() ) ?>"><?php echo fs_esc_html_inline( 'Install Update Now', 'install-update-now', $slug ) . ' [' . $update->version . ']' ?></a>
|
642 |
-
<?php endif ?>
|
643 |
-
<?php endif; ?>
|
644 |
-
</div>
|
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']) : ?>
|
652 |
-
<button class="button button-small activate-license-trigger <?php echo $fs->get_unique_affix() ?>"><?php fs_esc_html_echo_inline( 'Change License', 'change-license', $slug ) ?></button>
|
653 |
-
<?php endif ?>
|
654 |
-
<?php
|
655 |
-
elseif (/*in_array($p['id'], array('site_secret_key', 'site_id', 'site_public_key')) ||*/
|
656 |
-
( is_string( $user->secret_key ) && in_array( $p['id'], array(
|
657 |
-
'email',
|
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) */
|
664 |
-
fs_text_inline( 'What is your %s?', 'what-is-your-x', $slug ),
|
665 |
-
$p['title']
|
666 |
-
) ) ?>', '<?php echo $p['value'] ?>'); if (null == val || '' === val) return false; jQuery('input[name=fs_<?php echo $p['id'] ?>_<?php echo $fs->get_unique_affix() ?>]').val(val); return true;">
|
667 |
-
<input type="hidden" name="fs_action" value="update_<?php echo $p['id'] ?>">
|
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 ) ?>">
|
677 |
-
<?php endif ?>
|
678 |
-
</td>
|
679 |
-
<?php endif ?>
|
680 |
-
</tr>
|
681 |
-
<?php
|
682 |
-
if ( 'version' === $p['id'] && $is_premium ) {
|
683 |
-
/**
|
684 |
-
* If there's a row for the beta program, keep its background color
|
685 |
-
* the same as the version info row.
|
686 |
-
*
|
687 |
-
* @author Leo Fajardo (@leorw)
|
688 |
-
* @since 2.3.0
|
689 |
-
*/
|
690 |
-
continue;
|
691 |
-
}
|
692 |
-
|
693 |
-
$odd = ! $odd;
|
694 |
-
endforeach ?>
|
695 |
-
</table>
|
696 |
-
</div>
|
697 |
-
</div>
|
698 |
-
<?php if ( fs_is_network_admin() ) : ?>
|
699 |
-
<div id="fs_sites" class="postbox">
|
700 |
-
<h3><span class="dashicons dashicons-networking"></span> <?php fs_esc_html_echo_inline( 'Sites', 'sites', $slug ) ?></h3>
|
701 |
-
<div class="fs-header-actions">
|
702 |
-
<?php if ( ! $is_whitelabeled ) : ?>
|
703 |
-
<?php $has_license = is_object( $license ) ?>
|
704 |
-
<?php if ( $has_license || ( $show_upgrade && $is_premium ) ) : ?>
|
705 |
-
<?php
|
706 |
-
$activate_license_button_text = $has_license ?
|
707 |
-
fs_esc_html_inline( 'Change License', 'change-license', $slug ) :
|
708 |
-
fs_esc_html_inline( 'Activate License', 'activate-license', $slug );
|
709 |
-
?>
|
710 |
-
<a class="button<?php echo ( ! $has_license ? ' button-primary' : '' ) ?> activate-license-trigger <?php echo $fs->get_unique_affix() ?>" href="#"><?php echo $activate_license_button_text ?></a>
|
711 |
-
<?php endif ?>
|
712 |
-
<?php endif ?>
|
713 |
-
<input class="fs-search" type="text" placeholder="<?php fs_esc_attr_echo_inline( 'Search by address', 'search-by-address', $slug ) ?>..."><span class="dashicons dashicons-search"></span>
|
714 |
-
</div>
|
715 |
-
<div class="inside">
|
716 |
-
<div id="" class="fs-scrollable-table">
|
717 |
-
<div class="fs-table-head">
|
718 |
-
<table class="widefat">
|
719 |
-
<thead>
|
720 |
-
<tr>
|
721 |
-
<td><?php fs_esc_html_echo_inline('ID', 'id', $slug) ?></td>
|
722 |
-
<td><?php fs_esc_html_echo_inline('Address', 'address', $slug) ?></td>
|
723 |
-
<td><?php fs_esc_html_echo_inline('License', 'license', $slug) ?></td>
|
724 |
-
<td><?php fs_esc_html_echo_inline('Plan', 'plan', $slug) ?></td>
|
725 |
-
<td></td>
|
726 |
-
</tr>
|
727 |
-
</thead>
|
728 |
-
</table>
|
729 |
-
</div>
|
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>
|
742 |
-
</div>
|
743 |
-
</div>
|
744 |
-
<?php endif ?>
|
745 |
-
<?php if ( 0 < count( $addons_to_show ) ) : ?>
|
746 |
-
<!-- Add-Ons -->
|
747 |
-
<div class="postbox">
|
748 |
-
<div class="">
|
749 |
-
<!-- <div class="inside">-->
|
750 |
-
<table id="fs_addons" class="widefat">
|
751 |
-
<thead>
|
752 |
-
<tr>
|
753 |
-
<th><h3><?php echo esc_html( $addons_text ) ?></h3></th>
|
754 |
-
<th><?php fs_esc_html_echo_inline( 'ID', 'id', $slug ) ?></th>
|
755 |
-
<th><?php echo esc_html( $version_text ) ?></th>
|
756 |
-
<th><?php echo esc_html( $plan_text ) ?></th>
|
757 |
-
<th><?php fs_esc_html_echo_x_inline( 'License', 'as software license', 'license', $slug ) ?></th>
|
758 |
-
<th></th>
|
759 |
-
<?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
|
760 |
-
<th></th>
|
761 |
-
<?php endif ?>
|
762 |
-
</tr>
|
763 |
-
</thead>
|
764 |
-
<tbody>
|
765 |
-
<?php
|
766 |
-
$odd = true;
|
767 |
-
|
768 |
-
$installed_addons_ids_map = array_flip( $installed_addons_ids );
|
769 |
-
|
770 |
-
$addon_info_by_id = array();
|
771 |
-
$hide_all_addons_data = false;
|
772 |
-
|
773 |
-
if ( $fs->is_whitelabeled_by_flag() ) {
|
774 |
-
$hide_all_addons_data = true;
|
775 |
-
|
776 |
-
foreach ( $addons_to_show as $addon_id ) {
|
777 |
-
$is_addon_installed = isset( $installed_addons_ids_map[ $addon_id ] );
|
778 |
-
$addon_info = $fs->_get_addon_info( $addon_id, $is_addon_installed );
|
779 |
-
$is_addon_connected = $addon_info['is_connected'];
|
780 |
-
|
781 |
-
$fs_addon = ( $is_addon_connected && $is_addon_installed ) ?
|
782 |
-
freemius( $addon_id ) :
|
783 |
-
null;
|
784 |
-
|
785 |
-
$is_whitelabeled = is_object( $fs_addon ) ?
|
786 |
-
$fs_addon->is_whitelabeled( true ) :
|
787 |
-
$addon_info['is_whitelabeled'];
|
788 |
-
|
789 |
-
if ( ! $is_whitelabeled ) {
|
790 |
-
$hide_all_addons_data = false;
|
791 |
-
}
|
792 |
-
|
793 |
-
if ( $is_data_debug_mode ) {
|
794 |
-
$is_whitelabeled = false;
|
795 |
-
}
|
796 |
-
|
797 |
-
$addon_info_by_id[ $addon_id ] = $addon_info;
|
798 |
-
}
|
799 |
-
}
|
800 |
-
|
801 |
-
foreach ( $addons_to_show as $addon_id ) {
|
802 |
-
$is_addon_installed = isset( $installed_addons_ids_map[ $addon_id ] );
|
803 |
-
|
804 |
-
if (
|
805 |
-
$hide_all_addons_data &&
|
806 |
-
! $is_addon_installed &&
|
807 |
-
! file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $fs->get_addon_basename( $addon_id ) ) )
|
808 |
-
) {
|
809 |
-
continue;
|
810 |
-
}
|
811 |
-
|
812 |
-
$addon_view_params = array(
|
813 |
-
'parent_fs' => $fs,
|
814 |
-
'addon_id' => $addon_id,
|
815 |
-
'odd' => $odd,
|
816 |
-
'fs_blog_id' => $fs_blog_id,
|
817 |
-
'active_plugins_directories_map' => &$active_plugins_directories_map,
|
818 |
-
'is_addon_installed' => $is_addon_installed,
|
819 |
-
'addon_info' => isset( $addon_info_by_id[ $addon_id ] ) ?
|
820 |
-
$addon_info_by_id[ $addon_id ] :
|
821 |
-
$fs->_get_addon_info( $addon_id, $is_addon_installed ),
|
822 |
-
'is_whitelabeled' => ( $is_whitelabeled && ! $is_data_debug_mode )
|
823 |
-
);
|
824 |
-
|
825 |
-
fs_require_template(
|
826 |
-
'account/partials/addon.php',
|
827 |
-
$addon_view_params
|
828 |
-
);
|
829 |
-
|
830 |
-
$odd = ! $odd;
|
831 |
-
} ?>
|
832 |
-
</tbody>
|
833 |
-
</table>
|
834 |
-
</div>
|
835 |
-
</div>
|
836 |
-
<?php endif ?>
|
837 |
-
|
838 |
-
<?php $fs->do_action( 'after_account_details' ) ?>
|
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 |
-
}
|
846 |
-
?>
|
847 |
-
</div>
|
848 |
-
</div>
|
849 |
-
</div>
|
850 |
-
</div>
|
851 |
-
</div>
|
852 |
-
<?php
|
853 |
-
$subscription_cancellation_dialog_box_template_params = $fs->_get_subscription_cancellation_dialog_box_template_params( true );
|
854 |
-
if ( ! empty( $subscription_cancellation_dialog_box_template_params ) ) {
|
855 |
-
fs_require_template( 'forms/subscription-cancellation.php', $subscription_cancellation_dialog_box_template_params );
|
856 |
-
}
|
857 |
-
?>
|
858 |
-
<script type="text/javascript">
|
859 |
-
(function ($) {
|
860 |
-
var setLoading = function ($this, label) {
|
861 |
-
// Set loading mode.
|
862 |
-
$(document.body).css({'cursor': 'wait'});
|
863 |
-
|
864 |
-
$this.css({'cursor': 'wait'});
|
865 |
-
|
866 |
-
if ($this.is('input'))
|
867 |
-
$this.val(label);
|
868 |
-
else
|
869 |
-
$this.html(label);
|
870 |
-
|
871 |
-
setTimeout(function () {
|
872 |
-
$this.attr('disabled', 'disabled');
|
873 |
-
}, 200);
|
874 |
-
};
|
875 |
-
|
876 |
-
$('.fs-toggle-visibility').click(function () {
|
877 |
-
var
|
878 |
-
$this = $(this),
|
879 |
-
$parent = $this.closest('tr'),
|
880 |
-
$input = $parent.find('input');
|
881 |
-
|
882 |
-
$parent.find('code').toggle();
|
883 |
-
$input.toggle();
|
884 |
-
|
885 |
-
if ($input.is(':visible')) {
|
886 |
-
$this.html('<?php fs_esc_js_echo_x_inline( 'Hide', 'verb', 'hide', $slug ) ?>');
|
887 |
-
setTimeout(function () {
|
888 |
-
$input.select().focus();
|
889 |
-
}, 100);
|
890 |
-
}
|
891 |
-
else {
|
892 |
-
$this.html( '<?php fs_esc_js_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?>' );
|
893 |
-
}
|
894 |
-
});
|
895 |
-
|
896 |
-
$('.fs-toggle-tracking').click(function () {
|
897 |
-
setLoading(
|
898 |
-
$(this),
|
899 |
-
($(this).data('is-disconnected') ?
|
900 |
-
'<?php fs_esc_js_echo_inline('Opting in', 'opting-in' ) ?>' :
|
901 |
-
'<?php fs_esc_js_echo_inline('Opting out', 'opting-out' ) ?>') +
|
902 |
-
'...'
|
903 |
-
);
|
904 |
-
});
|
905 |
-
|
906 |
-
<?php
|
907 |
-
$plugin_title = $fs->get_plugin_title();
|
908 |
-
$processing_text = fs_esc_js_inline( 'Processing', 'processing' );
|
909 |
-
$confirmation_message = sprintf(
|
910 |
-
'%s %s',
|
911 |
-
sprintf( fs_esc_attr_inline( 'Get updates for bleeding edge Beta versions of %s.', 'get-beta-versions', $slug ), $plugin_title ),
|
912 |
-
sprintf( fs_esc_attr_inline( '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.', 'beta-version-update-caution', $slug ), $plugin_title )
|
913 |
-
);
|
914 |
-
?>
|
915 |
-
|
916 |
-
$( '.fs-toggle-beta-mode' ).click( function () {
|
917 |
-
var $checkbox = $( this ),
|
918 |
-
isChecked = $checkbox.is( ':checked' );
|
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' ) ?>',
|
926 |
-
security : '<?php echo $fs->get_ajax_security( 'set_beta_mode' ) ?>',
|
927 |
-
is_beta : isChecked,
|
928 |
-
module_id: <?php echo $fs->get_id() ?>
|
929 |
-
},
|
930 |
-
beforeSend: function () {
|
931 |
-
$checkbox.prop( 'disabled', true );
|
932 |
-
$checkbox.parent().find( 'span' ).text( '<?php echo $processing_text ?>' + '...' );
|
933 |
-
},
|
934 |
-
complete: function () {
|
935 |
-
$checkbox.prop( 'disabled', false );
|
936 |
-
$checkbox.parent().find( 'span' ).text( '<?php fs_esc_js_echo_inline( 'Join the Beta Program', 'join-beta', $slug ) ?>' );
|
937 |
-
}
|
938 |
-
} );
|
939 |
-
|
940 |
-
return true;
|
941 |
-
}
|
942 |
-
|
943 |
-
return false;
|
944 |
-
});
|
945 |
-
|
946 |
-
$('.fs-opt-in').click(function () {
|
947 |
-
setLoading($(this), '<?php fs_esc_js_echo_inline('Opting in', 'opting-in' ) ?>...');
|
948 |
-
});
|
949 |
-
|
950 |
-
$( '#fs_downgrade' ).submit(function( event ) {
|
951 |
-
event.preventDefault();
|
952 |
-
|
953 |
-
setLoading( $( this ).find( '.button' ), '<?php fs_esc_js_echo_inline( 'Downgrading', 'downgrading' ) ?>...' );
|
954 |
-
});
|
955 |
-
|
956 |
-
$('.fs-activate-license').click(function () {
|
957 |
-
setLoading($(this), '<?php fs_esc_js_echo_inline('Activating', 'activating' ) ?>...');
|
958 |
-
});
|
959 |
-
|
960 |
-
var $deactivateLicenseOrCancelTrial = $( '.fs-deactivate-license, .fs-cancel-trial' ),
|
961 |
-
$subscriptionCancellationModal = $( '.fs-modal-subscription-cancellation-<?php echo $fs->get_id() ?>' );
|
962 |
-
|
963 |
-
if ( 0 !== $subscriptionCancellationModal.length ) {
|
964 |
-
$subscriptionCancellationModal.on( '<?php echo $fs->get_action_tag( 'subscription_cancellation_action' ) ?>', function( evt, cancelSubscription ) {
|
965 |
-
setLoading(
|
966 |
-
$deactivateLicenseOrCancelTrial,
|
967 |
-
( ! $deactivateLicenseOrCancelTrial.hasClass( 'fs-cancel-trial' ) ?
|
968 |
-
'<?php fs_esc_js_echo_inline( 'Deactivating', 'deactivating', $slug ) ?>' :
|
969 |
-
'<?php echo esc_html( sprintf( fs_text_inline( 'Cancelling %s', 'cancelling-x', $slug ), fs_text_inline( 'trial', 'trial', $slug ) ) ) ?>' ) + '...'
|
970 |
-
);
|
971 |
-
|
972 |
-
$subscriptionCancellationModal.find( '.fs-modal-footer .button' ).addClass( 'disabled' );
|
973 |
-
$deactivateLicenseOrCancelTrial.unbind( 'click' );
|
974 |
-
|
975 |
-
if ( false === cancelSubscription || $deactivateLicenseOrCancelTrial.hasClass( 'fs-cancel-trial' ) ) {
|
976 |
-
$subscriptionCancellationModal.find( '.fs-modal-footer .button-primary' ).text( $deactivateLicenseOrCancelTrial.text() );
|
977 |
-
|
978 |
-
$deactivateLicenseOrCancelTrial[0].parentNode.submit();
|
979 |
-
} else {
|
980 |
-
var $form = $( 'input[value="downgrade_account"],input[value="cancel_trial"]' ).parent();
|
981 |
-
$form.prepend( '<input type="hidden" name="deactivate_license" value="true" />' );
|
982 |
-
|
983 |
-
$subscriptionCancellationModal.find( '.fs-modal-footer .button-primary' ).text( '<?php echo esc_js( sprintf(
|
984 |
-
fs_text_inline( 'Cancelling %s...', 'cancelling-x' , $slug ),
|
985 |
-
$is_paid_trial ?
|
986 |
-
fs_text_inline( 'trial', 'trial', $slug ) :
|
987 |
-
fs_text_inline( 'subscription', 'subscription', $slug )
|
988 |
-
) ) ?>' );
|
989 |
-
|
990 |
-
$form.submit();
|
991 |
-
}
|
992 |
-
});
|
993 |
-
}
|
994 |
-
|
995 |
-
$deactivateLicenseOrCancelTrial.click(function() {
|
996 |
-
var $this = $( this );
|
997 |
-
if ( $this.hasClass( 'fs-cancel-trial' ) ) {
|
998 |
-
$subscriptionCancellationModal.find( '.fs-modal-panel' ).find( 'ul.subscription-actions, .fs-price-increase-warning' ).remove();
|
999 |
-
$subscriptionCancellationModal.find( '.fs-modal-panel > p' ).text( <?php echo json_encode( $cancel_trial_confirm_text ) ?> );
|
1000 |
-
$subscriptionCancellationModal.trigger( 'showModal' );
|
1001 |
-
} else if (confirm('<?php fs_esc_attr_echo_inline( 'Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?', 'deactivate-license-confirm', $slug ) ?>')) {
|
1002 |
-
var $this = $(this);
|
1003 |
-
|
1004 |
-
if ( 0 !== $subscriptionCancellationModal.length ) {
|
1005 |
-
$subscriptionCancellationModal.trigger( 'showModal' );
|
1006 |
-
} else {
|
1007 |
-
setLoading( $this, '<?php fs_esc_js_echo_inline( 'Deactivating', 'deactivating', $slug ) ?>...' );
|
1008 |
-
$this[0].parentNode.submit();
|
1009 |
-
}
|
1010 |
-
}
|
1011 |
-
|
1012 |
-
return false;
|
1013 |
-
});
|
1014 |
-
|
1015 |
-
var $sitesSection = $('#fs_sites'),
|
1016 |
-
$sitesTable = $sitesSection.find('.fs-scrollable-table'),
|
1017 |
-
$sitesTableRows = $sitesTable.find('.fs-site-details');
|
1018 |
-
|
1019 |
-
$('.fs-show-install-details').click(function(){
|
1020 |
-
var installID = $(this).parents('.fs-site-details').attr('data-install-id');
|
1021 |
-
$sitesSection.find('.fs-install-details[data-install-id=' + installID + ']').toggle();
|
1022 |
-
});
|
1023 |
-
|
1024 |
-
|
1025 |
-
var adjustColumnWidth = function($table) {
|
1026 |
-
var $headerColumns = $table.find('.fs-table-head td'),
|
1027 |
-
$bodyColumns = $table.find('.fs-table-body tr:first > td');
|
1028 |
-
|
1029 |
-
for (var i = 0, len = $headerColumns.length; i < len; i++) {
|
1030 |
-
$($headerColumns[i]).width($($bodyColumns[i]).width());
|
1031 |
-
}
|
1032 |
-
for (i = 0, len = $headerColumns.length; i < len; i++) {
|
1033 |
-
$($bodyColumns[i]).width($($headerColumns[i]).width());
|
1034 |
-
}
|
1035 |
-
};
|
1036 |
-
|
1037 |
-
adjustColumnWidth($sitesTable);
|
1038 |
-
|
1039 |
-
$sitesSection.find('.fs-search').keyup(function(){
|
1040 |
-
var search = $(this).val().trim();
|
1041 |
-
|
1042 |
-
if ('' === search){
|
1043 |
-
// Show all.
|
1044 |
-
$sitesTableRows.show();
|
1045 |
-
return;
|
1046 |
-
}
|
1047 |
-
|
1048 |
-
var url;
|
1049 |
-
|
1050 |
-
$sitesTableRows.each(function(index){
|
1051 |
-
url = $(this).find('.fs-field-url').html();
|
1052 |
-
|
1053 |
-
if (-1 < url.indexOf(search)){
|
1054 |
-
$(this).show();
|
1055 |
-
} else {
|
1056 |
-
$(this).hide();
|
1057 |
-
}
|
1058 |
-
});
|
1059 |
-
});
|
1060 |
-
|
1061 |
-
$( '.fs-toggle-whitelabel-mode' ).click( function () {
|
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' ) ?>',
|
1069 |
-
security : '<?php echo $fs->get_ajax_security( 'toggle_whitelabel_mode' ) ?>',
|
1070 |
-
module_id: <?php echo $fs->get_id() ?>
|
1071 |
-
},
|
1072 |
-
beforeSend: function () {
|
1073 |
-
$toggleLink.parent().text( '<?php
|
1074 |
-
$is_whitelabeled ?
|
1075 |
-
fs_esc_html_echo_inline( 'Disabling white-label mode', 'disabling-whitelabel-mode' ) :
|
1076 |
-
fs_esc_html_echo_inline( 'Enabling white-label mode', 'enabling-whitelabel-mode' )
|
1077 |
-
?>' + '...' );
|
1078 |
-
},
|
1079 |
-
complete: function () {
|
1080 |
-
location.reload();
|
1081 |
-
}
|
1082 |
-
} );
|
1083 |
-
});
|
1084 |
-
})(jQuery);
|
1085 |
-
</script>
|
1086 |
-
<?php
|
1087 |
-
if ( $has_tabs ) {
|
1088 |
-
$fs->_add_tabs_after_content();
|
1089 |
-
}
|
1090 |
-
|
1091 |
-
$params = array(
|
1092 |
-
'page' => 'account',
|
1093 |
-
'module_id' => $fs->get_id(),
|
1094 |
-
'module_type' => $fs->get_module_type(),
|
1095 |
-
'module_slug' => $slug,
|
1096 |
-
'module_version' => $fs->get_plugin_version(),
|
1097 |
-
);
|
1098 |
fs_require_template( 'powered-by.php', $params );
|
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 1.0.3
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
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 |
+
/**
|
22 |
+
* @var FS_Plugin_Tag $update
|
23 |
+
*/
|
24 |
+
$update = $fs->has_release_on_freemius() ?
|
25 |
+
$fs->get_update( false, false, WP_FS__TIME_24_HOURS_IN_SEC / 24 ) :
|
26 |
+
null;
|
27 |
+
|
28 |
+
if ( is_object($update) ) {
|
29 |
+
/**
|
30 |
+
* This logic is particularly required for multisite environment.
|
31 |
+
* If a module is site activated (not network) and not on the main site,
|
32 |
+
* the module will NOT be executed on the network level, therefore, the
|
33 |
+
* custom updates logic will not be executed as well, so unless we force
|
34 |
+
* the injection of the update into the updates transient, premium updates
|
35 |
+
* will not work.
|
36 |
+
*
|
37 |
+
* @author Vova Feldman (@svovaf)
|
38 |
+
* @since 2.0.0
|
39 |
+
*/
|
40 |
+
$updater = FS_Plugin_Updater::instance( $fs );
|
41 |
+
$updater->set_update_data( $update );
|
42 |
+
}
|
43 |
+
|
44 |
+
$is_paying = $fs->is_paying();
|
45 |
+
$user = $fs->get_user();
|
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 ) ?
|
52 |
+
$fs->_get_subscription( $license->id ) :
|
53 |
+
null );
|
54 |
+
$plan = $fs->get_plan();
|
55 |
+
$is_active_subscription = ( is_object( $subscription ) && $subscription->is_active() );
|
56 |
+
$is_paid_trial = $fs->is_paid_trial();
|
57 |
+
$has_paid_plan = $fs->apply_filters( 'has_paid_plan_account', $fs->has_paid_plan() );
|
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();
|
68 |
+
|
69 |
+
if ( ! empty( $ids_of_installs_activated_with_foreign_licenses ) ) {
|
70 |
+
$fs->_add_user_change_dialog_box( $ids_of_installs_activated_with_foreign_licenses );
|
71 |
+
}
|
72 |
+
|
73 |
+
if ( $fs->is_whitelabeled( true ) || $fs->is_data_debug_mode() ) {
|
74 |
+
$fs->_add_data_debug_mode_dialog_box();
|
75 |
+
}
|
76 |
+
|
77 |
+
if ( fs_request_get_bool( 'auto_install' ) ) {
|
78 |
+
$fs->_add_auto_installation_dialog_box();
|
79 |
+
}
|
80 |
+
|
81 |
+
if ( fs_request_get_bool( 'activate_license' ) ) {
|
82 |
+
// Open the license activation dialog box on the account page.
|
83 |
+
add_action( 'admin_footer', array(
|
84 |
+
&$fs,
|
85 |
+
'_open_license_activation_dialog_box'
|
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';
|
98 |
+
}
|
99 |
+
|
100 |
+
// Aliases.
|
101 |
+
$download_latest_text = fs_text_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $slug );
|
102 |
+
$downgrading_plan_text = fs_text_inline( 'Downgrading your plan', 'downgrading-plan', $slug );
|
103 |
+
$cancelling_subscription_text = fs_text_inline( 'Cancelling the subscription', 'cancelling-subscription', $slug );
|
104 |
+
/* translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription' */
|
105 |
+
$downgrade_x_confirm_text = fs_text_inline( '%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s.', 'downgrade-x-confirm', $slug );
|
106 |
+
$prices_increase_text = fs_text_inline( '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.', 'pricing-increase-warning', $slug );
|
107 |
+
$cancel_trial_confirm_text = fs_text_inline( 'Cancelling the trial will immediately block access to all premium features. Are you sure?', 'cancel-trial-confirm', $slug );
|
108 |
+
$after_downgrade_non_blocking_text = fs_text_inline( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.', 'after-downgrade-non-blocking', $slug );
|
109 |
+
$after_downgrade_blocking_text = fs_text_inline( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.', 'after-downgrade-blocking', $slug );
|
110 |
+
/* translators: %s: Plan title (e.g. "Professional") */
|
111 |
+
$activate_plan_text = fs_text_inline( 'Activate %s Plan', 'activate-x-plan', $slug );
|
112 |
+
$version_text = fs_text_x_inline( 'Version', 'product version', 'version', $slug );
|
113 |
+
/* translators: %s: Time period (e.g. Auto renews in "2 months") */
|
114 |
+
$renews_in_text = fs_text_inline( 'Auto renews in %s', 'renews-in', $slug );
|
115 |
+
/* translators: %s: Time period (e.g. Expires in "2 months") */
|
116 |
+
$expires_in_text = fs_text_inline( 'Expires in %s', 'expires-in', $slug );
|
117 |
+
$sync_license_text = fs_text_x_inline( 'Sync License', 'as synchronize license', 'sync-license', $slug );
|
118 |
+
$cancel_trial_text = fs_text_inline( 'Cancel Trial', 'cancel-trial', $slug );
|
119 |
+
$change_plan_text = fs_text_inline( 'Change Plan', 'change-plan', $slug );
|
120 |
+
$upgrade_text = fs_text_x_inline( 'Upgrade', 'verb', 'upgrade', $slug );
|
121 |
+
$addons_text = fs_text_inline( 'Add-Ons', 'add-ons', $slug );
|
122 |
+
$downgrade_text = fs_text_x_inline( 'Downgrade', 'verb', 'downgrade', $slug );
|
123 |
+
$trial_text = fs_text_x_inline( 'Trial', 'trial period', 'trial', $slug );
|
124 |
+
$free_text = fs_text_inline( 'Free', 'free', $slug );
|
125 |
+
$activate_text = fs_text_inline( 'Activate', 'activate', $slug );
|
126 |
+
$plan_text = fs_text_x_inline( 'Plan', 'as product pricing plan', 'plan', $slug );
|
127 |
+
$bundle_plan_text = fs_text_inline( 'Bundle Plan', 'bundle-plan', $slug );
|
128 |
+
|
129 |
+
$show_plan_row = true;
|
130 |
+
$show_license_row = is_object( $license );
|
131 |
+
|
132 |
+
$site_view_params = array();
|
133 |
+
|
134 |
+
if ( fs_is_network_admin() ) {
|
135 |
+
$sites = Freemius::get_sites();
|
136 |
+
$all_installs_plan_id = null;
|
137 |
+
$all_installs_license_id = ( $show_license_row ? $license->id : null );
|
138 |
+
foreach ( $sites as $s ) {
|
139 |
+
$site_info = $fs->get_site_info( $s );
|
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,
|
146 |
+
);
|
147 |
+
|
148 |
+
$site_view_params[] = $view_params;
|
149 |
+
|
150 |
+
if ( empty( $install ) ) {
|
151 |
+
continue;
|
152 |
+
}
|
153 |
+
|
154 |
+
if ( $show_plan_row ) {
|
155 |
+
if ( is_null( $all_installs_plan_id ) ) {
|
156 |
+
$all_installs_plan_id = $install->plan_id;
|
157 |
+
} else if ( $all_installs_plan_id != $install->plan_id ) {
|
158 |
+
$show_plan_row = false;
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
if ( $show_license_row && $all_installs_license_id != $install->license_id ) {
|
163 |
+
$show_license_row = false;
|
164 |
+
}
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
$has_bundle_license = false;
|
169 |
+
|
170 |
+
if ( is_object( $license ) &&
|
171 |
+
FS_Plugin_License::is_valid_id( $license->parent_license_id )
|
172 |
+
) {
|
173 |
+
// Context license has a parent license, therefore, the account has a bundle license.
|
174 |
+
$has_bundle_license = true;
|
175 |
+
}
|
176 |
+
|
177 |
+
$bundle_subscription = null;
|
178 |
+
$is_bundle_first_payment_pending = false;
|
179 |
+
|
180 |
+
if (
|
181 |
+
$show_plan_row &&
|
182 |
+
is_object( $license ) &&
|
183 |
+
$has_bundle_license
|
184 |
+
) {
|
185 |
+
$bundle_plan_title = strtoupper( $license->parent_plan_title );
|
186 |
+
$bundle_subscription = $fs->_get_subscription( $license->parent_license_id );
|
187 |
+
$is_bundle_first_payment_pending = $license->is_first_payment_pending();
|
188 |
+
}
|
189 |
+
|
190 |
+
$fs_blog_id = ( is_multisite() && ! is_network_admin() ) ?
|
191 |
+
get_current_blog_id() :
|
192 |
+
0;
|
193 |
+
|
194 |
+
$active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $fs_blog_id );
|
195 |
+
|
196 |
+
$is_premium = $fs->is_premium();
|
197 |
+
|
198 |
+
$account_addons = $fs->get_updated_account_addons();
|
199 |
+
$installed_addons = $fs->get_installed_addons();
|
200 |
+
$installed_addons_ids = array();
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Store the installed add-ons' IDs into a collection which will be used in determining the add-ons to show on the "Account" page, and at the same time try to find an add-on that is activated with a bundle license if the core product is not.
|
204 |
+
*
|
205 |
+
* @author Leo Fajardo
|
206 |
+
*
|
207 |
+
* @since 2.4.0
|
208 |
+
*/
|
209 |
+
foreach ( $installed_addons as $fs_addon ) {
|
210 |
+
$installed_addons_ids[] = $fs_addon->get_id();
|
211 |
+
|
212 |
+
if ( $has_bundle_license ) {
|
213 |
+
// We already have the context bundle license details, skip.
|
214 |
+
continue;
|
215 |
+
}
|
216 |
+
|
217 |
+
if (
|
218 |
+
$show_plan_row &&
|
219 |
+
$fs_addon->has_active_valid_license()
|
220 |
+
) {
|
221 |
+
$addon_license = $fs_addon->_get_license();
|
222 |
+
|
223 |
+
if ( FS_Plugin_License::is_valid_id( $addon_license->parent_license_id ) ) {
|
224 |
+
// Add-on's license is associated with a parent/bundle license.
|
225 |
+
$has_bundle_license = true;
|
226 |
+
|
227 |
+
$bundle_plan_title = strtoupper( $addon_license->parent_plan_title );
|
228 |
+
$bundle_subscription = $fs_addon->_get_subscription( $addon_license->parent_license_id );
|
229 |
+
$is_bundle_first_payment_pending = $addon_license->is_first_payment_pending();
|
230 |
+
}
|
231 |
+
}
|
232 |
+
}
|
233 |
+
|
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 ) ) : ?>
|
240 |
+
<h2 class="nav-tab-wrapper">
|
241 |
+
<a href="<?php echo $fs->get_account_url() ?>"
|
242 |
+
class="nav-tab nav-tab-active"><?php fs_esc_html_echo_inline( 'Account', 'account', $slug ) ?></a>
|
243 |
+
<?php if ( $fs->has_addons() ) : ?>
|
244 |
+
<a href="<?php echo $fs->_get_admin_page_url( 'addons' ) ?>"
|
245 |
+
class="nav-tab"><?php echo esc_html( $addons_text ) ?></a>
|
246 |
+
<?php endif ?>
|
247 |
+
<?php if ( $show_upgrade ) : ?>
|
248 |
+
<a href="<?php echo $fs->get_upgrade_url() ?>" class="nav-tab"><?php echo esc_html( $upgrade_text ) ?></a>
|
249 |
+
<?php if ( $fs->apply_filters( 'show_trial', true ) && ! $fs->is_trial_utilized() && $fs->has_trial_plan() ) : ?>
|
250 |
+
<a href="<?php echo $fs->get_trial_url() ?>" class="nav-tab"><?php fs_esc_html_echo_inline( 'Free Trial', 'free-trial', $slug ) ?></a>
|
251 |
+
<?php endif ?>
|
252 |
+
<?php endif ?>
|
253 |
+
</h2>
|
254 |
+
<?php endif ?>
|
255 |
+
|
256 |
+
<div id="poststuff">
|
257 |
+
<div id="fs_account">
|
258 |
+
<div class="has-sidebar has-right-sidebar">
|
259 |
+
<div class="has-sidebar-content">
|
260 |
+
<div class="postbox">
|
261 |
+
<h3><span class="dashicons dashicons-businessman"></span> <?php fs_esc_html_echo_inline( 'Account Details', 'account-details', $slug ) ?></h3>
|
262 |
+
<div class="fs-header-actions">
|
263 |
+
<ul>
|
264 |
+
<?php if ( $fs->is_whitelabeled( true ) ) : ?>
|
265 |
+
<li>
|
266 |
+
<a href="#" class="debug-license-trigger"><i class="dashicons dashicons-<?php echo $is_whitelabeled ? 'editor-code' : 'controls-pause' ?>"></i> <span><?php
|
267 |
+
if ( $is_whitelabeled ) {
|
268 |
+
fs_esc_html_echo_inline( 'Start Debug', 'start-debug-license', $slug );
|
269 |
+
} else {
|
270 |
+
fs_esc_html_echo_inline( 'Stop Debug', 'stop-debug-license', $slug );
|
271 |
+
}
|
272 |
+
?></span></a>
|
273 |
+
</li>
|
274 |
+
<li> • </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> • </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> • </li>
|
297 |
+
<?php endif ?>
|
298 |
+
<?php if ( $is_paying ) : ?>
|
299 |
+
<?php if ( ! fs_is_network_admin() ) : ?>
|
300 |
+
<li>
|
301 |
+
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
302 |
+
<input type="hidden" name="fs_action" value="deactivate_license">
|
303 |
+
<?php wp_nonce_field( 'deactivate_license' ) ?>
|
304 |
+
<a href="#" class="fs-deactivate-license"><i
|
305 |
+
class="dashicons dashicons-admin-network"></i> <?php fs_echo_inline( 'Deactivate License', 'deactivate-license', $slug ) ?>
|
306 |
+
</a>
|
307 |
+
</form>
|
308 |
+
</li>
|
309 |
+
<li> • </li>
|
310 |
+
<?php endif ?>
|
311 |
+
<?php if ( ! $license->is_lifetime() &&
|
312 |
+
$is_active_subscription
|
313 |
+
) : ?>
|
314 |
+
<li>
|
315 |
+
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
316 |
+
<input type="hidden" name="fs_action" value="downgrade_account">
|
317 |
+
<?php wp_nonce_field( 'downgrade_account' ) ?>
|
318 |
+
<a href="#"
|
319 |
+
onclick="if ( confirm('<?php echo esc_attr( sprintf(
|
320 |
+
$downgrade_x_confirm_text,
|
321 |
+
( $fs->is_only_premium() ? $cancelling_subscription_text : $downgrading_plan_text ),
|
322 |
+
$plan->title,
|
323 |
+
human_time_diff( time(), strtotime( $license->expiration ) )
|
324 |
+
) ) ?> <?php if ( ! $license->is_block_features ) {
|
325 |
+
echo esc_attr( sprintf( $after_downgrade_non_blocking_text, $plan->title, $fs->get_module_label( true ) ) );
|
326 |
+
} else {
|
327 |
+
echo esc_attr( sprintf( $after_downgrade_blocking_text, $plan->title ) );
|
328 |
+
}?> <?php echo esc_attr( $prices_increase_text ) ?> <?php fs_esc_attr_echo_inline( 'Are you sure you want to proceed?', 'proceed-confirmation', $slug ) ?>') ) this.parentNode.submit(); return false;"><i class="dashicons dashicons-download"></i> <?php echo esc_html( $fs->is_only_premium() ? fs_text_inline( 'Cancel Subscription', 'cancel-subscription', $slug ) : $downgrade_text ) ?></a>
|
329 |
+
</form>
|
330 |
+
</li>
|
331 |
+
<li> • </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>
|
337 |
+
</li>
|
338 |
+
<li> • </li>
|
339 |
+
<?php endif ?>
|
340 |
+
<?php elseif ( $is_paid_trial ) : ?>
|
341 |
+
<li>
|
342 |
+
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
343 |
+
<input type="hidden" name="fs_action" value="cancel_trial">
|
344 |
+
<?php wp_nonce_field( 'cancel_trial' ) ?>
|
345 |
+
<a href="#" class="fs-cancel-trial"><i
|
346 |
+
class="dashicons dashicons-download"></i> <?php echo esc_html( $cancel_trial_text ) ?></a>
|
347 |
+
</form>
|
348 |
+
</li>
|
349 |
+
<li> • </li>
|
350 |
+
<?php endif ?>
|
351 |
+
<?php endif ?>
|
352 |
+
<li>
|
353 |
+
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
354 |
+
<input type="hidden" name="fs_action" value="<?php echo $fs->get_unique_affix() ?>_sync_license">
|
355 |
+
<?php wp_nonce_field( $fs->get_unique_affix() . '_sync_license' ) ?>
|
356 |
+
<a href="#" onclick="this.parentNode.submit(); return false;"><i
|
357 |
+
class="dashicons dashicons-image-rotate"></i> <?php fs_esc_html_echo_x_inline( 'Sync', 'as synchronize', 'sync', $slug ) ?></a>
|
358 |
+
</form>
|
359 |
+
</li>
|
360 |
+
</ul>
|
361 |
+
</div>
|
362 |
+
<div class="inside">
|
363 |
+
<table id="fs_account_details" cellspacing="0" class="fs-key-value-table">
|
364 |
+
<?php
|
365 |
+
$hide_license_key = ( ! $show_license_row || $fs->apply_filters( 'hide_license_key', false ) );
|
366 |
+
|
367 |
+
$profile = array();
|
368 |
+
|
369 |
+
if ( ! $is_whitelabeled ) {
|
370 |
+
$profile[] = array(
|
371 |
+
'id' => 'user_name',
|
372 |
+
'title' => fs_text_inline( 'Name', 'name', $slug ),
|
373 |
+
'value' => $name
|
374 |
+
);
|
375 |
+
// if (isset($user->email) && false !== strpos($user->email, '@'))
|
376 |
+
$profile[] = array(
|
377 |
+
'id' => 'email',
|
378 |
+
'title' => fs_text_inline( 'Email', 'email', $slug ),
|
379 |
+
'value' => $user->email
|
380 |
+
);
|
381 |
+
|
382 |
+
if ( is_numeric( $user->id ) ) {
|
383 |
+
$profile[] = array(
|
384 |
+
'id' => 'user_id',
|
385 |
+
'title' => fs_text_inline( 'User ID', 'user-id', $slug ),
|
386 |
+
'value' => $user->id
|
387 |
+
);
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
$profile[] = array(
|
392 |
+
'id' => 'product',
|
393 |
+
'title' => ( $fs->is_plugin() ?
|
394 |
+
fs_text_inline( 'Plugin', 'plugin', $slug ) :
|
395 |
+
fs_text_inline( 'Theme', 'theme', $slug ) ),
|
396 |
+
'value' => $fs->get_plugin_title()
|
397 |
+
);
|
398 |
+
|
399 |
+
$profile[] = array(
|
400 |
+
'id' => 'product_id',
|
401 |
+
'title' => ( $fs->is_plugin() ?
|
402 |
+
fs_text_inline( 'Plugin', 'plugin', $slug ) :
|
403 |
+
fs_text_inline( 'Theme', 'theme', $slug ) ) . ' ' . fs_text_inline( 'ID', 'id', $slug ),
|
404 |
+
'value' => $fs->get_id()
|
405 |
+
);
|
406 |
+
|
407 |
+
if ( ! fs_is_network_admin()) {
|
408 |
+
$profile[] = array(
|
409 |
+
'id' => 'site_id',
|
410 |
+
'title' => fs_text_inline( 'Site ID', 'site-id', $slug ),
|
411 |
+
'value' => is_string( $site->id ) ?
|
412 |
+
$site->id :
|
413 |
+
fs_text_inline( 'No ID', 'no-id', $slug )
|
414 |
+
);
|
415 |
+
|
416 |
+
$profile[] = array(
|
417 |
+
'id' => 'site_public_key',
|
418 |
+
'title' => fs_text_inline( 'Public Key', 'public-key', $slug ),
|
419 |
+
'value' => $site->public_key
|
420 |
+
);
|
421 |
+
|
422 |
+
$profile[] = array(
|
423 |
+
'id' => 'site_secret_key',
|
424 |
+
'title' => fs_text_inline( 'Secret Key', 'secret-key', $slug ),
|
425 |
+
'value' => ( ( is_string( $site->secret_key ) ) ?
|
426 |
+
$site->secret_key :
|
427 |
+
fs_text_x_inline( 'No Secret', 'as secret encryption key missing', 'no-secret', $slug )
|
428 |
+
)
|
429 |
+
);
|
430 |
+
}
|
431 |
+
|
432 |
+
$profile[] = array(
|
433 |
+
'id' => 'version',
|
434 |
+
'title' => $version_text,
|
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' => '',
|
442 |
+
'value' => $site->is_beta
|
443 |
+
);
|
444 |
+
}
|
445 |
+
|
446 |
+
if ( $has_paid_plan || $has_bundle_license ) {
|
447 |
+
if ( $fs->is_trial() ) {
|
448 |
+
if ( $show_plan_row ) {
|
449 |
+
$profile[] = array(
|
450 |
+
'id' => 'plan',
|
451 |
+
'title' => $plan_text,
|
452 |
+
'value' => ( is_string( $trial_plan->name ) ?
|
453 |
+
strtoupper( $trial_plan->title ) :
|
454 |
+
fs_text_inline( 'Trial', 'trial', $slug ) )
|
455 |
+
);
|
456 |
+
}
|
457 |
+
} else {
|
458 |
+
if ( $show_plan_row ) {
|
459 |
+
$profile[] = array(
|
460 |
+
'id' => 'plan',
|
461 |
+
'title' => ( $has_bundle_license ? ucfirst( $fs->get_module_type() ) . ' ' : '' ) . $plan_text,
|
462 |
+
'value' => strtoupper( is_string( $plan->name ) ?
|
463 |
+
$plan->title :
|
464 |
+
strtoupper( $free_text )
|
465 |
+
)
|
466 |
+
);
|
467 |
+
|
468 |
+
if ( $has_bundle_license ) {
|
469 |
+
$profile[] = array(
|
470 |
+
'id' => 'bundle_plan',
|
471 |
+
'title' => $bundle_plan_text,
|
472 |
+
'value' => $bundle_plan_title
|
473 |
+
);
|
474 |
+
}
|
475 |
+
}
|
476 |
+
|
477 |
+
if ( is_object( $license ) ) {
|
478 |
+
if ( ! $hide_license_key ) {
|
479 |
+
$profile[] = array(
|
480 |
+
'id' => 'license_key',
|
481 |
+
'title' => fs_text_inline( 'License Key', $slug ),
|
482 |
+
'value' => $license->secret_key,
|
483 |
+
);
|
484 |
+
}
|
485 |
+
}
|
486 |
+
}
|
487 |
+
}
|
488 |
+
?>
|
489 |
+
<?php $odd = true;
|
490 |
+
foreach ( $profile as $p ) : ?>
|
491 |
+
<?php
|
492 |
+
if ( 'plan' === $p['id'] && ! $has_paid_plan ) {
|
493 |
+
// If plugin don't have any paid plans, there's no reason
|
494 |
+
// to show current plan.
|
495 |
+
continue;
|
496 |
+
}
|
497 |
+
?>
|
498 |
+
<tr class="fs-field-<?php echo $p['id'] ?><?php if ( $odd ) : ?> alternate<?php endif ?>">
|
499 |
+
<td>
|
500 |
+
<nobr><?php echo $p['title'] ?><?php echo ( ! empty( $p['title'] ) ) ? ':' : '' ?></nobr>
|
501 |
+
</td>
|
502 |
+
<td<?php if ( 'plan' === $p['id'] || 'bundle_plan' === $p['id'] ) { echo ' colspan="2"'; }?>>
|
503 |
+
<?php if ( in_array( $p['id'], array( 'license_key', 'site_secret_key' ) ) ) : ?>
|
504 |
+
<code><?php echo FS_Plugin_License::mask_secret_key_for_html( $p['value'] ) ?></code>
|
505 |
+
<?php if ( ! $is_whitelabeled ) : ?>
|
506 |
+
<input type="text" value="<?php echo htmlspecialchars( $p['value'] ) ?>" style="display: none"
|
507 |
+
readonly/>
|
508 |
+
<?php endif ?>
|
509 |
+
<?php elseif ( 'beta_program' === $p['id'] ) : ?>
|
510 |
+
<label>
|
511 |
+
<input type="checkbox" class="fs-toggle-beta-mode" <?php checked( true, $p['value'] ) ?>/><span><?php
|
512 |
+
fs_esc_html_echo_inline( 'Join the Beta program', 'join-beta', $slug )
|
513 |
+
?></span></label>
|
514 |
+
<?php else : ?>
|
515 |
+
<code><?php echo htmlspecialchars( $p['value'] ) ?></code>
|
516 |
+
<?php endif ?>
|
517 |
+
<?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
|
518 |
+
<label class="fs-tag fs-warn"><?php fs_esc_html_echo_inline( 'not verified', 'not-verified', $slug ) ?></label>
|
519 |
+
<?php endif ?>
|
520 |
+
<?php if ( 'plan' === $p['id'] ) : ?>
|
521 |
+
<?php if ( $fs->is_trial() ) : ?>
|
522 |
+
<label class="fs-tag fs-success"><?php echo esc_html( $trial_text ) ?></label>
|
523 |
+
<?php endif ?>
|
524 |
+
<?php if ( is_object( $license ) && ! $license->is_lifetime() ) : ?>
|
525 |
+
<?php if ( ! $is_active_subscription && ! $is_active_bundle_subscription && ! $license->is_first_payment_pending() ) : ?>
|
526 |
+
<?php $is_license_expired = $license->is_expired() ?>
|
527 |
+
<?php $expired_ago_text = ( fs_text_inline( 'Expired', 'expired', $slug ) . ' ' . fs_text_x_inline( '%s ago', 'x-ago', $slug ) ) ?>
|
528 |
+
<label
|
529 |
+
class="fs-tag <?php echo $is_license_expired ? 'fs-error' : 'fs-warn' ?>"><?php
|
530 |
+
echo esc_html( sprintf( $is_license_expired ? $expired_ago_text : $expires_in_text, human_time_diff( time(), strtotime( $license->expiration ) ) ) )
|
531 |
+
?></label>
|
532 |
+
<?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
|
533 |
+
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ) ?></label>
|
534 |
+
<?php endif ?>
|
535 |
+
<?php elseif ( $fs->is_trial() ) : ?>
|
536 |
+
<label class="fs-tag fs-warn"><?php echo esc_html( sprintf( $expires_in_text, human_time_diff( time(), strtotime( $site->trial_ends ) ) ) ) ?></label>
|
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',
|
552 |
+
);
|
553 |
+
fs_require_template( 'account/partials/activate-license-button.php', $view_params ); ?>
|
554 |
+
<?php else : ?>
|
555 |
+
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>"
|
556 |
+
method="POST" class="button-group">
|
557 |
+
<?php if ( $show_upgrade && $is_premium ) : ?>
|
558 |
+
<a class="button activate-license-trigger <?php echo $fs->get_unique_affix() ?>" href="#"><?php fs_esc_html_echo_inline( 'Activate License', 'activate-license', $slug ) ?></a>
|
559 |
+
<?php endif ?>
|
560 |
+
<input type="submit" class="button"
|
561 |
+
value="<?php echo esc_attr( $sync_license_text ) ?>">
|
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 ?
|
569 |
+
' button-primary fs-upgrade' :
|
570 |
+
' fs-change-plan'; ?> button-upgrade"><i
|
571 |
+
class="dashicons dashicons-cart"></i> <?php echo esc_html( $show_upgrade ? $upgrade_text : $change_plan_text ) ?></a>
|
572 |
+
<?php endif ?>
|
573 |
+
</form>
|
574 |
+
<?php endif ?>
|
575 |
+
</div>
|
576 |
+
<?php endif ?>
|
577 |
+
<?php elseif ( 'bundle_plan' === $p['id'] ) : ?>
|
578 |
+
<?php if ( is_object( $bundle_subscription ) ) : ?>
|
579 |
+
<?php if ( $is_active_bundle_subscription && ! $is_bundle_first_payment_pending ) : ?>
|
580 |
+
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $bundle_subscription->next_payment ) ) ) ) ?></label>
|
581 |
+
<?php endif ?>
|
582 |
+
<?php endif ?>
|
583 |
+
<?php elseif ( 'version' === $p['id'] && $has_paid_plan ) : ?>
|
584 |
+
<?php if ( $fs->has_premium_version() ) : ?>
|
585 |
+
<?php if ( $is_premium ) : ?>
|
586 |
+
<label
|
587 |
+
class="fs-tag fs-<?php echo $fs->can_use_premium_code() ? 'success' : 'warn' ?>"><?php fs_esc_html_echo_inline( 'Premium version', 'premium-version', $slug ) ?></label>
|
588 |
+
<?php elseif ( $fs->can_use_premium_code() ) : ?>
|
589 |
+
<label class="fs-tag fs-warn"><?php fs_esc_html_echo_inline( 'Free version', 'free-version', $slug ) ?></label>
|
590 |
+
<?php endif ?>
|
591 |
+
<?php endif ?>
|
592 |
+
<?php endif ?>
|
593 |
+
</td>
|
594 |
+
<?php if ( 'plan' !== $p['id'] && 'bundle_plan' !== $p['id'] ) : ?>
|
595 |
+
<td class="fs-right">
|
596 |
+
<?php if ( 'email' === $p['id'] && ! $user->is_verified() ) : ?>
|
597 |
+
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
598 |
+
<input type="hidden" name="fs_action" value="verify_email">
|
599 |
+
<?php wp_nonce_field( 'verify_email' ) ?>
|
600 |
+
<input type="submit" class="button button-small"
|
601 |
+
value="<?php fs_esc_attr_echo_inline( 'Verify Email', 'verify-email', $slug ) ?>">
|
602 |
+
</form>
|
603 |
+
<?php endif ?>
|
604 |
+
<?php if ( 'version' === $p['id'] ) : ?>
|
605 |
+
<?php if ( $fs->has_release_on_freemius() ) : ?>
|
606 |
+
<div class="button-group">
|
607 |
+
<?php if ( $is_paying || $fs->is_trial() ) : ?>
|
608 |
+
<?php if ( ! $fs->is_allowed_to_install() ) : ?>
|
609 |
+
<a target="_blank" rel="noopener" class="button button-primary"
|
610 |
+
href="<?php echo $fs->_get_latest_download_local_url() ?>"><?php
|
611 |
+
$download_version_text_suffix = ( is_object( $update ) ? ' [' . $update->version . ']' : '' );
|
612 |
+
|
613 |
+
$download_version_text = sprintf(
|
614 |
+
/* translators: %s: plan name (e.g. Download "Professional" Version) */
|
615 |
+
fs_text_inline( 'Download %s Version', 'download-x-version', $slug ),
|
616 |
+
( $fs->is_trial() ? $trial_plan->title : $plan->title )
|
617 |
+
) .
|
618 |
+
$download_version_text_suffix;
|
619 |
+
|
620 |
+
$download_version_text_length = function_exists( 'mb_strlen' ) ?
|
621 |
+
mb_strlen( $download_version_text ) :
|
622 |
+
strlen( $download_version_text );
|
623 |
+
|
624 |
+
if ( $download_version_text_length > 31 ) {
|
625 |
+
/**
|
626 |
+
* Try to limit the number of characters to 31 for now.
|
627 |
+
*
|
628 |
+
* @author Leo Fajardo (@leorw)
|
629 |
+
* @aince 2.3.2
|
630 |
+
*/
|
631 |
+
$download_version_text = fs_text_inline( 'Download Paid Version', 'download-paid-version', $slug ) . $download_version_text_suffix;
|
632 |
+
}
|
633 |
+
|
634 |
+
echo $download_version_text;
|
635 |
+
?></a>
|
636 |
+
<?php elseif ( is_object( $update ) ) : ?>
|
637 |
+
<?php
|
638 |
+
$module_type = $fs->get_module_type();
|
639 |
+
?>
|
640 |
+
<a class="button button-primary"
|
641 |
+
href="<?php echo wp_nonce_url( self_admin_url( "update.php?action=upgrade-{$module_type}&{$module_type}=" . $fs->get_plugin_basename() ), "upgrade-{$module_type}_" . $fs->get_plugin_basename() ) ?>"><?php echo fs_esc_html_inline( 'Install Update Now', 'install-update-now', $slug ) . ' [' . $update->version . ']' ?></a>
|
642 |
+
<?php endif ?>
|
643 |
+
<?php endif; ?>
|
644 |
+
</div>
|
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']) : ?>
|
652 |
+
<button class="button button-small activate-license-trigger <?php echo $fs->get_unique_affix() ?>"><?php fs_esc_html_echo_inline( 'Change License', 'change-license', $slug ) ?></button>
|
653 |
+
<?php endif ?>
|
654 |
+
<?php
|
655 |
+
elseif (/*in_array($p['id'], array('site_secret_key', 'site_id', 'site_public_key')) ||*/
|
656 |
+
( is_string( $user->secret_key ) && in_array( $p['id'], array(
|
657 |
+
'email',
|
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) */
|
664 |
+
fs_text_inline( 'What is your %s?', 'what-is-your-x', $slug ),
|
665 |
+
$p['title']
|
666 |
+
) ) ?>', '<?php echo $p['value'] ?>'); if (null == val || '' === val) return false; jQuery('input[name=fs_<?php echo $p['id'] ?>_<?php echo $fs->get_unique_affix() ?>]').val(val); return true;">
|
667 |
+
<input type="hidden" name="fs_action" value="update_<?php echo $p['id'] ?>">
|
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 ) ?>">
|
677 |
+
<?php endif ?>
|
678 |
+
</td>
|
679 |
+
<?php endif ?>
|
680 |
+
</tr>
|
681 |
+
<?php
|
682 |
+
if ( 'version' === $p['id'] && $is_premium ) {
|
683 |
+
/**
|
684 |
+
* If there's a row for the beta program, keep its background color
|
685 |
+
* the same as the version info row.
|
686 |
+
*
|
687 |
+
* @author Leo Fajardo (@leorw)
|
688 |
+
* @since 2.3.0
|
689 |
+
*/
|
690 |
+
continue;
|
691 |
+
}
|
692 |
+
|
693 |
+
$odd = ! $odd;
|
694 |
+
endforeach ?>
|
695 |
+
</table>
|
696 |
+
</div>
|
697 |
+
</div>
|
698 |
+
<?php if ( fs_is_network_admin() ) : ?>
|
699 |
+
<div id="fs_sites" class="postbox">
|
700 |
+
<h3><span class="dashicons dashicons-networking"></span> <?php fs_esc_html_echo_inline( 'Sites', 'sites', $slug ) ?></h3>
|
701 |
+
<div class="fs-header-actions">
|
702 |
+
<?php if ( ! $is_whitelabeled ) : ?>
|
703 |
+
<?php $has_license = is_object( $license ) ?>
|
704 |
+
<?php if ( $has_license || ( $show_upgrade && $is_premium ) ) : ?>
|
705 |
+
<?php
|
706 |
+
$activate_license_button_text = $has_license ?
|
707 |
+
fs_esc_html_inline( 'Change License', 'change-license', $slug ) :
|
708 |
+
fs_esc_html_inline( 'Activate License', 'activate-license', $slug );
|
709 |
+
?>
|
710 |
+
<a class="button<?php echo ( ! $has_license ? ' button-primary' : '' ) ?> activate-license-trigger <?php echo $fs->get_unique_affix() ?>" href="#"><?php echo $activate_license_button_text ?></a>
|
711 |
+
<?php endif ?>
|
712 |
+
<?php endif ?>
|
713 |
+
<input class="fs-search" type="text" placeholder="<?php fs_esc_attr_echo_inline( 'Search by address', 'search-by-address', $slug ) ?>..."><span class="dashicons dashicons-search"></span>
|
714 |
+
</div>
|
715 |
+
<div class="inside">
|
716 |
+
<div id="" class="fs-scrollable-table">
|
717 |
+
<div class="fs-table-head">
|
718 |
+
<table class="widefat">
|
719 |
+
<thead>
|
720 |
+
<tr>
|
721 |
+
<td><?php fs_esc_html_echo_inline('ID', 'id', $slug) ?></td>
|
722 |
+
<td><?php fs_esc_html_echo_inline('Address', 'address', $slug) ?></td>
|
723 |
+
<td><?php fs_esc_html_echo_inline('License', 'license', $slug) ?></td>
|
724 |
+
<td><?php fs_esc_html_echo_inline('Plan', 'plan', $slug) ?></td>
|
725 |
+
<td></td>
|
726 |
+
</tr>
|
727 |
+
</thead>
|
728 |
+
</table>
|
729 |
+
</div>
|
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>
|
742 |
+
</div>
|
743 |
+
</div>
|
744 |
+
<?php endif ?>
|
745 |
+
<?php if ( 0 < count( $addons_to_show ) ) : ?>
|
746 |
+
<!-- Add-Ons -->
|
747 |
+
<div class="postbox">
|
748 |
+
<div class="">
|
749 |
+
<!-- <div class="inside">-->
|
750 |
+
<table id="fs_addons" class="widefat">
|
751 |
+
<thead>
|
752 |
+
<tr>
|
753 |
+
<th><h3><?php echo esc_html( $addons_text ) ?></h3></th>
|
754 |
+
<th><?php fs_esc_html_echo_inline( 'ID', 'id', $slug ) ?></th>
|
755 |
+
<th><?php echo esc_html( $version_text ) ?></th>
|
756 |
+
<th><?php echo esc_html( $plan_text ) ?></th>
|
757 |
+
<th><?php fs_esc_html_echo_x_inline( 'License', 'as software license', 'license', $slug ) ?></th>
|
758 |
+
<th></th>
|
759 |
+
<?php if ( defined( 'WP_FS__DEV_MODE' ) && WP_FS__DEV_MODE ) : ?>
|
760 |
+
<th></th>
|
761 |
+
<?php endif ?>
|
762 |
+
</tr>
|
763 |
+
</thead>
|
764 |
+
<tbody>
|
765 |
+
<?php
|
766 |
+
$odd = true;
|
767 |
+
|
768 |
+
$installed_addons_ids_map = array_flip( $installed_addons_ids );
|
769 |
+
|
770 |
+
$addon_info_by_id = array();
|
771 |
+
$hide_all_addons_data = false;
|
772 |
+
|
773 |
+
if ( $fs->is_whitelabeled_by_flag() ) {
|
774 |
+
$hide_all_addons_data = true;
|
775 |
+
|
776 |
+
foreach ( $addons_to_show as $addon_id ) {
|
777 |
+
$is_addon_installed = isset( $installed_addons_ids_map[ $addon_id ] );
|
778 |
+
$addon_info = $fs->_get_addon_info( $addon_id, $is_addon_installed );
|
779 |
+
$is_addon_connected = $addon_info['is_connected'];
|
780 |
+
|
781 |
+
$fs_addon = ( $is_addon_connected && $is_addon_installed ) ?
|
782 |
+
freemius( $addon_id ) :
|
783 |
+
null;
|
784 |
+
|
785 |
+
$is_whitelabeled = is_object( $fs_addon ) ?
|
786 |
+
$fs_addon->is_whitelabeled( true ) :
|
787 |
+
$addon_info['is_whitelabeled'];
|
788 |
+
|
789 |
+
if ( ! $is_whitelabeled ) {
|
790 |
+
$hide_all_addons_data = false;
|
791 |
+
}
|
792 |
+
|
793 |
+
if ( $is_data_debug_mode ) {
|
794 |
+
$is_whitelabeled = false;
|
795 |
+
}
|
796 |
+
|
797 |
+
$addon_info_by_id[ $addon_id ] = $addon_info;
|
798 |
+
}
|
799 |
+
}
|
800 |
+
|
801 |
+
foreach ( $addons_to_show as $addon_id ) {
|
802 |
+
$is_addon_installed = isset( $installed_addons_ids_map[ $addon_id ] );
|
803 |
+
|
804 |
+
if (
|
805 |
+
$hide_all_addons_data &&
|
806 |
+
! $is_addon_installed &&
|
807 |
+
! file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $fs->get_addon_basename( $addon_id ) ) )
|
808 |
+
) {
|
809 |
+
continue;
|
810 |
+
}
|
811 |
+
|
812 |
+
$addon_view_params = array(
|
813 |
+
'parent_fs' => $fs,
|
814 |
+
'addon_id' => $addon_id,
|
815 |
+
'odd' => $odd,
|
816 |
+
'fs_blog_id' => $fs_blog_id,
|
817 |
+
'active_plugins_directories_map' => &$active_plugins_directories_map,
|
818 |
+
'is_addon_installed' => $is_addon_installed,
|
819 |
+
'addon_info' => isset( $addon_info_by_id[ $addon_id ] ) ?
|
820 |
+
$addon_info_by_id[ $addon_id ] :
|
821 |
+
$fs->_get_addon_info( $addon_id, $is_addon_installed ),
|
822 |
+
'is_whitelabeled' => ( $is_whitelabeled && ! $is_data_debug_mode )
|
823 |
+
);
|
824 |
+
|
825 |
+
fs_require_template(
|
826 |
+
'account/partials/addon.php',
|
827 |
+
$addon_view_params
|
828 |
+
);
|
829 |
+
|
830 |
+
$odd = ! $odd;
|
831 |
+
} ?>
|
832 |
+
</tbody>
|
833 |
+
</table>
|
834 |
+
</div>
|
835 |
+
</div>
|
836 |
+
<?php endif ?>
|
837 |
+
|
838 |
+
<?php $fs->do_action( 'after_account_details' ) ?>
|
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 |
+
}
|
846 |
+
?>
|
847 |
+
</div>
|
848 |
+
</div>
|
849 |
+
</div>
|
850 |
+
</div>
|
851 |
+
</div>
|
852 |
+
<?php
|
853 |
+
$subscription_cancellation_dialog_box_template_params = $fs->_get_subscription_cancellation_dialog_box_template_params( true );
|
854 |
+
if ( ! empty( $subscription_cancellation_dialog_box_template_params ) ) {
|
855 |
+
fs_require_template( 'forms/subscription-cancellation.php', $subscription_cancellation_dialog_box_template_params );
|
856 |
+
}
|
857 |
+
?>
|
858 |
+
<script type="text/javascript">
|
859 |
+
(function ($) {
|
860 |
+
var setLoading = function ($this, label) {
|
861 |
+
// Set loading mode.
|
862 |
+
$(document.body).css({'cursor': 'wait'});
|
863 |
+
|
864 |
+
$this.css({'cursor': 'wait'});
|
865 |
+
|
866 |
+
if ($this.is('input'))
|
867 |
+
$this.val(label);
|
868 |
+
else
|
869 |
+
$this.html(label);
|
870 |
+
|
871 |
+
setTimeout(function () {
|
872 |
+
$this.attr('disabled', 'disabled');
|
873 |
+
}, 200);
|
874 |
+
};
|
875 |
+
|
876 |
+
$('.fs-toggle-visibility').click(function () {
|
877 |
+
var
|
878 |
+
$this = $(this),
|
879 |
+
$parent = $this.closest('tr'),
|
880 |
+
$input = $parent.find('input');
|
881 |
+
|
882 |
+
$parent.find('code').toggle();
|
883 |
+
$input.toggle();
|
884 |
+
|
885 |
+
if ($input.is(':visible')) {
|
886 |
+
$this.html('<?php fs_esc_js_echo_x_inline( 'Hide', 'verb', 'hide', $slug ) ?>');
|
887 |
+
setTimeout(function () {
|
888 |
+
$input.select().focus();
|
889 |
+
}, 100);
|
890 |
+
}
|
891 |
+
else {
|
892 |
+
$this.html( '<?php fs_esc_js_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?>' );
|
893 |
+
}
|
894 |
+
});
|
895 |
+
|
896 |
+
$('.fs-toggle-tracking').click(function () {
|
897 |
+
setLoading(
|
898 |
+
$(this),
|
899 |
+
($(this).data('is-disconnected') ?
|
900 |
+
'<?php fs_esc_js_echo_inline('Opting in', 'opting-in' ) ?>' :
|
901 |
+
'<?php fs_esc_js_echo_inline('Opting out', 'opting-out' ) ?>') +
|
902 |
+
'...'
|
903 |
+
);
|
904 |
+
});
|
905 |
+
|
906 |
+
<?php
|
907 |
+
$plugin_title = $fs->get_plugin_title();
|
908 |
+
$processing_text = fs_esc_js_inline( 'Processing', 'processing' );
|
909 |
+
$confirmation_message = sprintf(
|
910 |
+
'%s %s',
|
911 |
+
sprintf( fs_esc_attr_inline( 'Get updates for bleeding edge Beta versions of %s.', 'get-beta-versions', $slug ), $plugin_title ),
|
912 |
+
sprintf( fs_esc_attr_inline( '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.', 'beta-version-update-caution', $slug ), $plugin_title )
|
913 |
+
);
|
914 |
+
?>
|
915 |
+
|
916 |
+
$( '.fs-toggle-beta-mode' ).click( function () {
|
917 |
+
var $checkbox = $( this ),
|
918 |
+
isChecked = $checkbox.is( ':checked' );
|
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' ) ?>',
|
926 |
+
security : '<?php echo $fs->get_ajax_security( 'set_beta_mode' ) ?>',
|
927 |
+
is_beta : isChecked,
|
928 |
+
module_id: <?php echo $fs->get_id() ?>
|
929 |
+
},
|
930 |
+
beforeSend: function () {
|
931 |
+
$checkbox.prop( 'disabled', true );
|
932 |
+
$checkbox.parent().find( 'span' ).text( '<?php echo $processing_text ?>' + '...' );
|
933 |
+
},
|
934 |
+
complete: function () {
|
935 |
+
$checkbox.prop( 'disabled', false );
|
936 |
+
$checkbox.parent().find( 'span' ).text( '<?php fs_esc_js_echo_inline( 'Join the Beta Program', 'join-beta', $slug ) ?>' );
|
937 |
+
}
|
938 |
+
} );
|
939 |
+
|
940 |
+
return true;
|
941 |
+
}
|
942 |
+
|
943 |
+
return false;
|
944 |
+
});
|
945 |
+
|
946 |
+
$('.fs-opt-in').click(function () {
|
947 |
+
setLoading($(this), '<?php fs_esc_js_echo_inline('Opting in', 'opting-in' ) ?>...');
|
948 |
+
});
|
949 |
+
|
950 |
+
$( '#fs_downgrade' ).submit(function( event ) {
|
951 |
+
event.preventDefault();
|
952 |
+
|
953 |
+
setLoading( $( this ).find( '.button' ), '<?php fs_esc_js_echo_inline( 'Downgrading', 'downgrading' ) ?>...' );
|
954 |
+
});
|
955 |
+
|
956 |
+
$('.fs-activate-license').click(function () {
|
957 |
+
setLoading($(this), '<?php fs_esc_js_echo_inline('Activating', 'activating' ) ?>...');
|
958 |
+
});
|
959 |
+
|
960 |
+
var $deactivateLicenseOrCancelTrial = $( '.fs-deactivate-license, .fs-cancel-trial' ),
|
961 |
+
$subscriptionCancellationModal = $( '.fs-modal-subscription-cancellation-<?php echo $fs->get_id() ?>' );
|
962 |
+
|
963 |
+
if ( 0 !== $subscriptionCancellationModal.length ) {
|
964 |
+
$subscriptionCancellationModal.on( '<?php echo $fs->get_action_tag( 'subscription_cancellation_action' ) ?>', function( evt, cancelSubscription ) {
|
965 |
+
setLoading(
|
966 |
+
$deactivateLicenseOrCancelTrial,
|
967 |
+
( ! $deactivateLicenseOrCancelTrial.hasClass( 'fs-cancel-trial' ) ?
|
968 |
+
'<?php fs_esc_js_echo_inline( 'Deactivating', 'deactivating', $slug ) ?>' :
|
969 |
+
'<?php echo esc_html( sprintf( fs_text_inline( 'Cancelling %s', 'cancelling-x', $slug ), fs_text_inline( 'trial', 'trial', $slug ) ) ) ?>' ) + '...'
|
970 |
+
);
|
971 |
+
|
972 |
+
$subscriptionCancellationModal.find( '.fs-modal-footer .button' ).addClass( 'disabled' );
|
973 |
+
$deactivateLicenseOrCancelTrial.unbind( 'click' );
|
974 |
+
|
975 |
+
if ( false === cancelSubscription || $deactivateLicenseOrCancelTrial.hasClass( 'fs-cancel-trial' ) ) {
|
976 |
+
$subscriptionCancellationModal.find( '.fs-modal-footer .button-primary' ).text( $deactivateLicenseOrCancelTrial.text() );
|
977 |
+
|
978 |
+
$deactivateLicenseOrCancelTrial[0].parentNode.submit();
|
979 |
+
} else {
|
980 |
+
var $form = $( 'input[value="downgrade_account"],input[value="cancel_trial"]' ).parent();
|
981 |
+
$form.prepend( '<input type="hidden" name="deactivate_license" value="true" />' );
|
982 |
+
|
983 |
+
$subscriptionCancellationModal.find( '.fs-modal-footer .button-primary' ).text( '<?php echo esc_js( sprintf(
|
984 |
+
fs_text_inline( 'Cancelling %s...', 'cancelling-x' , $slug ),
|
985 |
+
$is_paid_trial ?
|
986 |
+
fs_text_inline( 'trial', 'trial', $slug ) :
|
987 |
+
fs_text_inline( 'subscription', 'subscription', $slug )
|
988 |
+
) ) ?>' );
|
989 |
+
|
990 |
+
$form.submit();
|
991 |
+
}
|
992 |
+
});
|
993 |
+
}
|
994 |
+
|
995 |
+
$deactivateLicenseOrCancelTrial.click(function() {
|
996 |
+
var $this = $( this );
|
997 |
+
if ( $this.hasClass( 'fs-cancel-trial' ) ) {
|
998 |
+
$subscriptionCancellationModal.find( '.fs-modal-panel' ).find( 'ul.subscription-actions, .fs-price-increase-warning' ).remove();
|
999 |
+
$subscriptionCancellationModal.find( '.fs-modal-panel > p' ).text( <?php echo json_encode( $cancel_trial_confirm_text ) ?> );
|
1000 |
+
$subscriptionCancellationModal.trigger( 'showModal' );
|
1001 |
+
} else if (confirm('<?php fs_esc_attr_echo_inline( 'Deactivating your license will block all premium features, but will enable activating the license on another site. Are you sure you want to proceed?', 'deactivate-license-confirm', $slug ) ?>')) {
|
1002 |
+
var $this = $(this);
|
1003 |
+
|
1004 |
+
if ( 0 !== $subscriptionCancellationModal.length ) {
|
1005 |
+
$subscriptionCancellationModal.trigger( 'showModal' );
|
1006 |
+
} else {
|
1007 |
+
setLoading( $this, '<?php fs_esc_js_echo_inline( 'Deactivating', 'deactivating', $slug ) ?>...' );
|
1008 |
+
$this[0].parentNode.submit();
|
1009 |
+
}
|
1010 |
+
}
|
1011 |
+
|
1012 |
+
return false;
|
1013 |
+
});
|
1014 |
+
|
1015 |
+
var $sitesSection = $('#fs_sites'),
|
1016 |
+
$sitesTable = $sitesSection.find('.fs-scrollable-table'),
|
1017 |
+
$sitesTableRows = $sitesTable.find('.fs-site-details');
|
1018 |
+
|
1019 |
+
$('.fs-show-install-details').click(function(){
|
1020 |
+
var installID = $(this).parents('.fs-site-details').attr('data-install-id');
|
1021 |
+
$sitesSection.find('.fs-install-details[data-install-id=' + installID + ']').toggle();
|
1022 |
+
});
|
1023 |
+
|
1024 |
+
|
1025 |
+
var adjustColumnWidth = function($table) {
|
1026 |
+
var $headerColumns = $table.find('.fs-table-head td'),
|
1027 |
+
$bodyColumns = $table.find('.fs-table-body tr:first > td');
|
1028 |
+
|
1029 |
+
for (var i = 0, len = $headerColumns.length; i < len; i++) {
|
1030 |
+
$($headerColumns[i]).width($($bodyColumns[i]).width());
|
1031 |
+
}
|
1032 |
+
for (i = 0, len = $headerColumns.length; i < len; i++) {
|
1033 |
+
$($bodyColumns[i]).width($($headerColumns[i]).width());
|
1034 |
+
}
|
1035 |
+
};
|
1036 |
+
|
1037 |
+
adjustColumnWidth($sitesTable);
|
1038 |
+
|
1039 |
+
$sitesSection.find('.fs-search').keyup(function(){
|
1040 |
+
var search = $(this).val().trim();
|
1041 |
+
|
1042 |
+
if ('' === search){
|
1043 |
+
// Show all.
|
1044 |
+
$sitesTableRows.show();
|
1045 |
+
return;
|
1046 |
+
}
|
1047 |
+
|
1048 |
+
var url;
|
1049 |
+
|
1050 |
+
$sitesTableRows.each(function(index){
|
1051 |
+
url = $(this).find('.fs-field-url').html();
|
1052 |
+
|
1053 |
+
if (-1 < url.indexOf(search)){
|
1054 |
+
$(this).show();
|
1055 |
+
} else {
|
1056 |
+
$(this).hide();
|
1057 |
+
}
|
1058 |
+
});
|
1059 |
+
});
|
1060 |
+
|
1061 |
+
$( '.fs-toggle-whitelabel-mode' ).click( function () {
|
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' ) ?>',
|
1069 |
+
security : '<?php echo $fs->get_ajax_security( 'toggle_whitelabel_mode' ) ?>',
|
1070 |
+
module_id: <?php echo $fs->get_id() ?>
|
1071 |
+
},
|
1072 |
+
beforeSend: function () {
|
1073 |
+
$toggleLink.parent().text( '<?php
|
1074 |
+
$is_whitelabeled ?
|
1075 |
+
fs_esc_html_echo_inline( 'Disabling white-label mode', 'disabling-whitelabel-mode' ) :
|
1076 |
+
fs_esc_html_echo_inline( 'Enabling white-label mode', 'enabling-whitelabel-mode' )
|
1077 |
+
?>' + '...' );
|
1078 |
+
},
|
1079 |
+
complete: function () {
|
1080 |
+
location.reload();
|
1081 |
+
}
|
1082 |
+
} );
|
1083 |
+
});
|
1084 |
+
})(jQuery);
|
1085 |
+
</script>
|
1086 |
+
<?php
|
1087 |
+
if ( $has_tabs ) {
|
1088 |
+
$fs->_add_tabs_after_content();
|
1089 |
+
}
|
1090 |
+
|
1091 |
+
$params = array(
|
1092 |
+
'page' => 'account',
|
1093 |
+
'module_id' => $fs->get_id(),
|
1094 |
+
'module_type' => $fs->get_module_type(),
|
1095 |
+
'module_slug' => $slug,
|
1096 |
+
'module_version' => $fs->get_plugin_version(),
|
1097 |
+
);
|
1098 |
fs_require_template( 'powered-by.php', $params );
|
freemius/templates/account/partials/site.php
CHANGED
@@ -1,352 +1,352 @@
|
|
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.0.0
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var array $VARS
|
15 |
-
* @var Freemius $fs
|
16 |
-
* @var FS_Plugin_License $main_license
|
17 |
-
*/
|
18 |
-
$fs = $VARS['freemius'];
|
19 |
-
$slug = $fs->get_slug();
|
20 |
-
$site = $VARS['site'];
|
21 |
-
$main_license = $VARS['license'];
|
22 |
-
$is_data_debug_mode = $fs->is_data_debug_mode();
|
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'];
|
30 |
-
$is_registered = ! empty( $install );
|
31 |
-
$license = null;
|
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 |
-
?>
|
39 |
-
<tr class="fs-site-details" data-blog-id="<?php echo $blog_id ?>"<?php if ( $is_registered ) : ?> data-install-id="<?php echo $install->id ?>"<?php endif ?>>
|
40 |
-
<!-- Install ID or Opt-in option -->
|
41 |
-
<td><?php if ( $is_registered ) : ?>
|
42 |
-
<?php echo $install->id ?>
|
43 |
-
<?php else : ?>
|
44 |
-
<?php $action = 'opt_in' ?>
|
45 |
-
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
46 |
-
<input type="hidden" name="fs_action" value="<?php echo $action ?>">
|
47 |
-
<?php wp_nonce_field( trim( "{$action}:{$blog_id}", ':' ) ) ?>
|
48 |
-
<input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
|
49 |
-
<button class="fs-opt-in button button-small"><?php fs_esc_html_echo_inline( 'Opt In', 'opt-in', $slug ) ?></button>
|
50 |
-
</form>
|
51 |
-
<?php endif ?>
|
52 |
-
</td>
|
53 |
-
<!--/ Install ID or Opt-in option -->
|
54 |
-
|
55 |
-
<!-- Site URL -->
|
56 |
-
<td class="fs-field-url fs-main-column"><?php echo fs_strip_url_protocol( $site['url'] ) ?></td>
|
57 |
-
<!--/ Site URL -->
|
58 |
-
|
59 |
-
<!-- License Activation / Deactivation -->
|
60 |
-
<td><?php if ( $has_paid_plan ) {
|
61 |
-
$view_params = array(
|
62 |
-
'freemius' => $fs,
|
63 |
-
'slug' => $slug,
|
64 |
-
'blog_id' => $blog_id,
|
65 |
-
'class' => 'button-small',
|
66 |
-
);
|
67 |
-
|
68 |
-
$license = null;
|
69 |
-
if ( $is_registered ) {
|
70 |
-
$view_params['install_id'] = $install->id;
|
71 |
-
$view_params['is_localhost'] = $install->is_localhost();
|
72 |
-
|
73 |
-
$has_license = FS_Plugin_License::is_valid_id( $install->license_id );
|
74 |
-
$license = $has_license ?
|
75 |
-
$fs->_get_license_by_id( $install->license_id ) :
|
76 |
-
null;
|
77 |
-
} else {
|
78 |
-
$view_params['is_localhost'] = FS_Site::is_localhost_by_address( $site['url'] );
|
79 |
-
}
|
80 |
-
|
81 |
-
if ( ! $is_whitelabeled ) {
|
82 |
-
if ( is_object( $license ) ) {
|
83 |
-
$view_params['license'] = $license;
|
84 |
-
|
85 |
-
// Show license deactivation button.
|
86 |
-
fs_require_template( 'account/partials/deactivate-license-button.php', $view_params );
|
87 |
-
} else {
|
88 |
-
if ( is_object( $main_license ) && $main_license->can_activate( $view_params['is_localhost'] ) ) {
|
89 |
-
// Main license is available for activation.
|
90 |
-
$available_license = $main_license;
|
91 |
-
} else {
|
92 |
-
// Try to find any available license for activation.
|
93 |
-
$available_license = $fs->_get_available_premium_license( $view_params['is_localhost'] );
|
94 |
-
}
|
95 |
-
|
96 |
-
if ( is_object( $available_license ) ) {
|
97 |
-
$premium_plan = $fs->_get_plan_by_id( $available_license->plan_id );
|
98 |
-
|
99 |
-
$view_params['license'] = $available_license;
|
100 |
-
$view_params['class'] .= ' button-primary';
|
101 |
-
$view_params['plan'] = $premium_plan;
|
102 |
-
|
103 |
-
fs_require_template( 'account/partials/activate-license-button.php', $view_params );
|
104 |
-
}
|
105 |
-
}
|
106 |
-
}
|
107 |
-
} ?></td>
|
108 |
-
<!--/ License Activation / Deactivation -->
|
109 |
-
|
110 |
-
<!-- Plan -->
|
111 |
-
<td><?php if ( $is_registered ) : ?>
|
112 |
-
<?php
|
113 |
-
if ( ! $has_paid_plan ) {
|
114 |
-
$plan_title = $free_text;
|
115 |
-
} else {
|
116 |
-
if ( $install->is_trial() ) {
|
117 |
-
if ( is_object( $trial_plan ) && $trial_plan->id == $install->trial_plan_id ) {
|
118 |
-
$plan_title = is_string( $trial_plan->name ) ?
|
119 |
-
strtoupper( $trial_plan->title ) :
|
120 |
-
fs_text_inline( 'Trial', 'trial', $slug );
|
121 |
-
} else {
|
122 |
-
$plan_title = fs_text_inline( 'Trial', 'trial', $slug );
|
123 |
-
}
|
124 |
-
} else {
|
125 |
-
$plan = $fs->_get_plan_by_id( $install->plan_id );
|
126 |
-
$plan_title = strtoupper( is_string( $plan->title ) ?
|
127 |
-
$plan->title :
|
128 |
-
strtoupper( $free_text )
|
129 |
-
);
|
130 |
-
}
|
131 |
-
}
|
132 |
-
?>
|
133 |
-
<code><?php echo $plan_title ?></code>
|
134 |
-
<?php endif ?></td>
|
135 |
-
<!--/ Plan -->
|
136 |
-
|
137 |
-
<!-- More details button -->
|
138 |
-
<td><?php if ( $is_registered ) : ?>
|
139 |
-
<button class="fs-show-install-details button button-small">More details <i
|
140 |
-
class="dashicons dashicons-arrow-right-alt2"></i>
|
141 |
-
</button><?php endif ?></td>
|
142 |
-
<!--/ More details button -->
|
143 |
-
</tr>
|
144 |
-
<?php if ( $is_registered ) : ?>
|
145 |
-
<!-- More details -->
|
146 |
-
<tr class="fs-install-details" data-install-id="<?php echo $install->id ?>" style="display: none">
|
147 |
-
<td colspan="5">
|
148 |
-
<table class="widefat fs-key-value-table">
|
149 |
-
<tbody>
|
150 |
-
<?php $row_index = 0 ?>
|
151 |
-
<!-- Blog ID -->
|
152 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
153 |
-
echo ' class="alternate"';
|
154 |
-
} ?>>
|
155 |
-
<td>
|
156 |
-
<nobr><?php fs_esc_html_echo_inline( 'Blog ID', 'blog-id', $slug ) ?>:</nobr>
|
157 |
-
</td>
|
158 |
-
<td><code><?php echo $blog_id ?></code></td>
|
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>
|
173 |
-
</tr>
|
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
|
181 |
-
*/
|
182 |
-
$user = Freemius::_get_user_by_id( $install->user_id ) ?>
|
183 |
-
<?php if ( is_object( $user ) ) : ?>
|
184 |
-
<!-- User Name -->
|
185 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
186 |
-
echo ' class="alternate"';
|
187 |
-
} ?>>
|
188 |
-
<td>
|
189 |
-
<nobr><?php fs_esc_html_echo_inline( 'Owner Name', 'owner-name', $slug ) ?>:</nobr>
|
190 |
-
</td>
|
191 |
-
<td colspan="2"><code><?php echo htmlspecialchars( $user->get_name() ) ?></code></td>
|
192 |
-
</tr>
|
193 |
-
<?php $row_index ++ ?>
|
194 |
-
<!--/ User Name -->
|
195 |
-
|
196 |
-
<!-- User Email -->
|
197 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
198 |
-
echo ' class="alternate"';
|
199 |
-
} ?>>
|
200 |
-
<td>
|
201 |
-
<nobr><?php fs_esc_html_echo_inline( 'Owner Email', 'owner-email', $slug ) ?>:</nobr>
|
202 |
-
</td>
|
203 |
-
<td colspan="2"><code><?php echo htmlspecialchars( $user->email ) ?></code></td>
|
204 |
-
</tr>
|
205 |
-
<?php $row_index ++ ?>
|
206 |
-
<!--/ User Email -->
|
207 |
-
|
208 |
-
<!-- User ID -->
|
209 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
210 |
-
echo ' class="alternate"';
|
211 |
-
} ?>>
|
212 |
-
<td>
|
213 |
-
<nobr><?php fs_esc_html_echo_inline( 'Owner ID', 'owner-id', $slug ) ?>:</nobr>
|
214 |
-
</td>
|
215 |
-
<td colspan="2"><code><?php echo $user->id ?></code></td>
|
216 |
-
</tr>
|
217 |
-
<?php $row_index ++ ?>
|
218 |
-
<!--/ User ID -->
|
219 |
-
<?php endif ?>
|
220 |
-
<?php endif ?>
|
221 |
-
|
222 |
-
<!-- Public Key -->
|
223 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
224 |
-
echo ' class="alternate"';
|
225 |
-
} ?>>
|
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 -->
|
233 |
-
|
234 |
-
<!-- Secret Key -->
|
235 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
236 |
-
echo ' class="alternate"';
|
237 |
-
} ?>>
|
238 |
-
<td>
|
239 |
-
<nobr><?php fs_esc_html_echo_inline( 'Secret Key', 'secret-key', $slug ) ?>:</nobr>
|
240 |
-
</td>
|
241 |
-
<td>
|
242 |
-
<code><?php echo FS_Plugin_License::mask_secret_key_for_html( $install->secret_key ) ?></code>
|
243 |
-
<?php if ( ! $is_whitelabeled ) : ?>
|
244 |
-
<input type="text" value="<?php echo htmlspecialchars( $install->secret_key ) ?>"
|
245 |
-
style="display: none" readonly/></td>
|
246 |
-
<?php endif ?>
|
247 |
-
<?php if ( ! $is_whitelabeled ) : ?>
|
248 |
-
<td><button class="button button-small fs-toggle-visibility"><?php fs_esc_html_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?></button></td>
|
249 |
-
<?php endif ?>
|
250 |
-
</tr>
|
251 |
-
<?php $row_index ++ ?>
|
252 |
-
<!--/ Secret Key -->
|
253 |
-
|
254 |
-
<?php if ( is_object( $license ) ) : ?>
|
255 |
-
<!-- License Key -->
|
256 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
257 |
-
echo ' class="alternate"';
|
258 |
-
} ?>>
|
259 |
-
<td>
|
260 |
-
<nobr><?php fs_esc_html_echo_inline( 'License Key', 'license-key', $slug ) ?>:</nobr>
|
261 |
-
</td>
|
262 |
-
<td>
|
263 |
-
<code><?php echo $license->get_html_escaped_masked_secret_key() ?></code>
|
264 |
-
<?php if ( ! $is_whitelabeled ) : ?>
|
265 |
-
<input type="text" value="<?php echo htmlspecialchars( $license->secret_key ) ?>"
|
266 |
-
style="display: none" readonly/></td>
|
267 |
-
<?php endif ?>
|
268 |
-
<?php if ( ! $is_whitelabeled ) : ?>
|
269 |
-
<td>
|
270 |
-
<button class="button button-small fs-toggle-visibility"><?php fs_esc_html_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?></button>
|
271 |
-
<button class="button button-small activate-license-trigger <?php echo $fs->get_unique_affix() ?>"><?php fs_esc_html_echo_inline( 'Change License', 'change-license', $slug ) ?></button>
|
272 |
-
</td>
|
273 |
-
<?php endif ?>
|
274 |
-
</tr>
|
275 |
-
<?php $row_index ++ ?>
|
276 |
-
<!--/ License Key -->
|
277 |
-
|
278 |
-
<?php if ( ! is_object( $main_license ) || $main_license->id != $license->id ) : ?>
|
279 |
-
<?php $subscription = $fs->_get_subscription( $license->id ) ?>
|
280 |
-
<?php if ( ! $license->is_lifetime() && is_object( $subscription ) ) : ?>
|
281 |
-
<!-- Subscription -->
|
282 |
-
<tr <?php if ( 1 == $row_index % 2 ) {
|
283 |
-
echo ' class="alternate"';
|
284 |
-
} ?>>
|
285 |
-
<td>
|
286 |
-
<nobr><?php fs_esc_html_echo_inline( 'Subscription', 'subscription', $slug ) ?>:</nobr>
|
287 |
-
</td>
|
288 |
-
<?php
|
289 |
-
$is_active_subscription = $subscription->is_active();
|
290 |
-
|
291 |
-
$renews_in_text = fs_text_inline( 'Auto renews in %s', 'renews-in', $slug );
|
292 |
-
/* translators: %s: Time period (e.g. Expires in "2 months") */
|
293 |
-
$expires_in_text = fs_text_inline( 'Expires in %s', 'expires-in', $slug );
|
294 |
-
?>
|
295 |
-
<td>
|
296 |
-
<code><?php echo $subscription->id ?> - <?php
|
297 |
-
echo ( 12 == $subscription->billing_cycle ?
|
298 |
-
_fs_text_inline( 'Annual', 'annual', $slug ) :
|
299 |
-
_fs_text_inline( 'Monthly', 'monthly', $slug )
|
300 |
-
);
|
301 |
-
?>
|
302 |
-
</code>
|
303 |
-
<?php if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) : ?>
|
304 |
-
<label class="fs-tag fs-warn"><?php echo esc_html( sprintf( $expires_in_text, human_time_diff( time(), strtotime( $license->expiration ) ) ) ) ?></label>
|
305 |
-
<?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
|
306 |
-
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ) ?></label>
|
307 |
-
<?php endif ?>
|
308 |
-
</td>
|
309 |
-
<td><?php if ( $is_active_subscription ) : ?>
|
310 |
-
<?php
|
311 |
-
$downgrading_plan_text = fs_text_inline( 'Downgrading your plan', 'downgrading-plan', $slug );
|
312 |
-
$cancelling_subscription_text = fs_text_inline( 'Cancelling the subscription', 'cancelling-subscription', $slug );
|
313 |
-
/* translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription' */
|
314 |
-
$downgrade_x_confirm_text = fs_text_inline( '%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s.', 'downgrade-x-confirm', $slug );
|
315 |
-
$prices_increase_text = fs_text_inline( '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.', 'pricing-increase-warning', $slug );
|
316 |
-
$after_downgrade_non_blocking_text = fs_text_inline( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.', 'after-downgrade-non-blocking', $slug );
|
317 |
-
$after_downgrade_blocking_text = fs_text_inline( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.', 'after-downgrade-blocking', $slug );
|
318 |
-
$downgrade_text = fs_text_x_inline( 'Downgrade', 'verb', 'downgrade', $slug );
|
319 |
-
|
320 |
-
$human_readable_license_expiration = human_time_diff( time(), strtotime( $license->expiration ) );
|
321 |
-
$downgrade_confirmation_message = sprintf(
|
322 |
-
$downgrade_x_confirm_text,
|
323 |
-
( $fs->is_only_premium() ? $cancelling_subscription_text : $downgrading_plan_text ),
|
324 |
-
$plan->title,
|
325 |
-
$human_readable_license_expiration
|
326 |
-
);
|
327 |
-
|
328 |
-
$after_downgrade_message = ! $license->is_block_features ?
|
329 |
-
sprintf( $after_downgrade_non_blocking_text, $plan->title, $fs->get_module_label( true ) ) :
|
330 |
-
sprintf( $after_downgrade_blocking_text, $plan->title );
|
331 |
-
?>
|
332 |
-
<?php $action = 'downgrade_account' ?>
|
333 |
-
<form id="fs_downgrade" action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
334 |
-
<input type="hidden" name="fs_action" value="<?php echo $action ?>">
|
335 |
-
<?php wp_nonce_field( trim( "{$action}:{$blog_id}", ':' ) ) ?>
|
336 |
-
<input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
|
337 |
-
<button class="button button-small" onclick="if (confirm('<?php echo esc_attr( $downgrade_confirmation_message . ' ' . $after_downgrade_message . ' ' . $prices_increase_text ) ?>')) { this.parentNode.submit(); } else { return false; }"><?php echo $downgrade_text ?></button>
|
338 |
-
</form>
|
339 |
-
<?php endif ?></td>
|
340 |
-
</tr>
|
341 |
-
<?php $row_index ++ ?>
|
342 |
-
<?php endif ?>
|
343 |
-
<!--/ Subscription -->
|
344 |
-
<?php endif ?>
|
345 |
-
<?php endif ?>
|
346 |
-
|
347 |
-
</tbody>
|
348 |
-
</table>
|
349 |
-
</td>
|
350 |
-
</tr>
|
351 |
-
<!--/ More details -->
|
352 |
<?php endif ?>
|
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.0.0
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var array $VARS
|
15 |
+
* @var Freemius $fs
|
16 |
+
* @var FS_Plugin_License $main_license
|
17 |
+
*/
|
18 |
+
$fs = $VARS['freemius'];
|
19 |
+
$slug = $fs->get_slug();
|
20 |
+
$site = $VARS['site'];
|
21 |
+
$main_license = $VARS['license'];
|
22 |
+
$is_data_debug_mode = $fs->is_data_debug_mode();
|
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'];
|
30 |
+
$is_registered = ! empty( $install );
|
31 |
+
$license = null;
|
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 |
+
?>
|
39 |
+
<tr class="fs-site-details" data-blog-id="<?php echo $blog_id ?>"<?php if ( $is_registered ) : ?> data-install-id="<?php echo $install->id ?>"<?php endif ?>>
|
40 |
+
<!-- Install ID or Opt-in option -->
|
41 |
+
<td><?php if ( $is_registered ) : ?>
|
42 |
+
<?php echo $install->id ?>
|
43 |
+
<?php else : ?>
|
44 |
+
<?php $action = 'opt_in' ?>
|
45 |
+
<form action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
46 |
+
<input type="hidden" name="fs_action" value="<?php echo $action ?>">
|
47 |
+
<?php wp_nonce_field( trim( "{$action}:{$blog_id}", ':' ) ) ?>
|
48 |
+
<input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
|
49 |
+
<button class="fs-opt-in button button-small"><?php fs_esc_html_echo_inline( 'Opt In', 'opt-in', $slug ) ?></button>
|
50 |
+
</form>
|
51 |
+
<?php endif ?>
|
52 |
+
</td>
|
53 |
+
<!--/ Install ID or Opt-in option -->
|
54 |
+
|
55 |
+
<!-- Site URL -->
|
56 |
+
<td class="fs-field-url fs-main-column"><?php echo fs_strip_url_protocol( $site['url'] ) ?></td>
|
57 |
+
<!--/ Site URL -->
|
58 |
+
|
59 |
+
<!-- License Activation / Deactivation -->
|
60 |
+
<td><?php if ( $has_paid_plan ) {
|
61 |
+
$view_params = array(
|
62 |
+
'freemius' => $fs,
|
63 |
+
'slug' => $slug,
|
64 |
+
'blog_id' => $blog_id,
|
65 |
+
'class' => 'button-small',
|
66 |
+
);
|
67 |
+
|
68 |
+
$license = null;
|
69 |
+
if ( $is_registered ) {
|
70 |
+
$view_params['install_id'] = $install->id;
|
71 |
+
$view_params['is_localhost'] = $install->is_localhost();
|
72 |
+
|
73 |
+
$has_license = FS_Plugin_License::is_valid_id( $install->license_id );
|
74 |
+
$license = $has_license ?
|
75 |
+
$fs->_get_license_by_id( $install->license_id ) :
|
76 |
+
null;
|
77 |
+
} else {
|
78 |
+
$view_params['is_localhost'] = FS_Site::is_localhost_by_address( $site['url'] );
|
79 |
+
}
|
80 |
+
|
81 |
+
if ( ! $is_whitelabeled ) {
|
82 |
+
if ( is_object( $license ) ) {
|
83 |
+
$view_params['license'] = $license;
|
84 |
+
|
85 |
+
// Show license deactivation button.
|
86 |
+
fs_require_template( 'account/partials/deactivate-license-button.php', $view_params );
|
87 |
+
} else {
|
88 |
+
if ( is_object( $main_license ) && $main_license->can_activate( $view_params['is_localhost'] ) ) {
|
89 |
+
// Main license is available for activation.
|
90 |
+
$available_license = $main_license;
|
91 |
+
} else {
|
92 |
+
// Try to find any available license for activation.
|
93 |
+
$available_license = $fs->_get_available_premium_license( $view_params['is_localhost'] );
|
94 |
+
}
|
95 |
+
|
96 |
+
if ( is_object( $available_license ) ) {
|
97 |
+
$premium_plan = $fs->_get_plan_by_id( $available_license->plan_id );
|
98 |
+
|
99 |
+
$view_params['license'] = $available_license;
|
100 |
+
$view_params['class'] .= ' button-primary';
|
101 |
+
$view_params['plan'] = $premium_plan;
|
102 |
+
|
103 |
+
fs_require_template( 'account/partials/activate-license-button.php', $view_params );
|
104 |
+
}
|
105 |
+
}
|
106 |
+
}
|
107 |
+
} ?></td>
|
108 |
+
<!--/ License Activation / Deactivation -->
|
109 |
+
|
110 |
+
<!-- Plan -->
|
111 |
+
<td><?php if ( $is_registered ) : ?>
|
112 |
+
<?php
|
113 |
+
if ( ! $has_paid_plan ) {
|
114 |
+
$plan_title = $free_text;
|
115 |
+
} else {
|
116 |
+
if ( $install->is_trial() ) {
|
117 |
+
if ( is_object( $trial_plan ) && $trial_plan->id == $install->trial_plan_id ) {
|
118 |
+
$plan_title = is_string( $trial_plan->name ) ?
|
119 |
+
strtoupper( $trial_plan->title ) :
|
120 |
+
fs_text_inline( 'Trial', 'trial', $slug );
|
121 |
+
} else {
|
122 |
+
$plan_title = fs_text_inline( 'Trial', 'trial', $slug );
|
123 |
+
}
|
124 |
+
} else {
|
125 |
+
$plan = $fs->_get_plan_by_id( $install->plan_id );
|
126 |
+
$plan_title = strtoupper( is_string( $plan->title ) ?
|
127 |
+
$plan->title :
|
128 |
+
strtoupper( $free_text )
|
129 |
+
);
|
130 |
+
}
|
131 |
+
}
|
132 |
+
?>
|
133 |
+
<code><?php echo $plan_title ?></code>
|
134 |
+
<?php endif ?></td>
|
135 |
+
<!--/ Plan -->
|
136 |
+
|
137 |
+
<!-- More details button -->
|
138 |
+
<td><?php if ( $is_registered ) : ?>
|
139 |
+
<button class="fs-show-install-details button button-small">More details <i
|
140 |
+
class="dashicons dashicons-arrow-right-alt2"></i>
|
141 |
+
</button><?php endif ?></td>
|
142 |
+
<!--/ More details button -->
|
143 |
+
</tr>
|
144 |
+
<?php if ( $is_registered ) : ?>
|
145 |
+
<!-- More details -->
|
146 |
+
<tr class="fs-install-details" data-install-id="<?php echo $install->id ?>" style="display: none">
|
147 |
+
<td colspan="5">
|
148 |
+
<table class="widefat fs-key-value-table">
|
149 |
+
<tbody>
|
150 |
+
<?php $row_index = 0 ?>
|
151 |
+
<!-- Blog ID -->
|
152 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
153 |
+
echo ' class="alternate"';
|
154 |
+
} ?>>
|
155 |
+
<td>
|
156 |
+
<nobr><?php fs_esc_html_echo_inline( 'Blog ID', 'blog-id', $slug ) ?>:</nobr>
|
157 |
+
</td>
|
158 |
+
<td><code><?php echo $blog_id ?></code></td>
|
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>
|
173 |
+
</tr>
|
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
|
181 |
+
*/
|
182 |
+
$user = Freemius::_get_user_by_id( $install->user_id ) ?>
|
183 |
+
<?php if ( is_object( $user ) ) : ?>
|
184 |
+
<!-- User Name -->
|
185 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
186 |
+
echo ' class="alternate"';
|
187 |
+
} ?>>
|
188 |
+
<td>
|
189 |
+
<nobr><?php fs_esc_html_echo_inline( 'Owner Name', 'owner-name', $slug ) ?>:</nobr>
|
190 |
+
</td>
|
191 |
+
<td colspan="2"><code><?php echo htmlspecialchars( $user->get_name() ) ?></code></td>
|
192 |
+
</tr>
|
193 |
+
<?php $row_index ++ ?>
|
194 |
+
<!--/ User Name -->
|
195 |
+
|
196 |
+
<!-- User Email -->
|
197 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
198 |
+
echo ' class="alternate"';
|
199 |
+
} ?>>
|
200 |
+
<td>
|
201 |
+
<nobr><?php fs_esc_html_echo_inline( 'Owner Email', 'owner-email', $slug ) ?>:</nobr>
|
202 |
+
</td>
|
203 |
+
<td colspan="2"><code><?php echo htmlspecialchars( $user->email ) ?></code></td>
|
204 |
+
</tr>
|
205 |
+
<?php $row_index ++ ?>
|
206 |
+
<!--/ User Email -->
|
207 |
+
|
208 |
+
<!-- User ID -->
|
209 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
210 |
+
echo ' class="alternate"';
|
211 |
+
} ?>>
|
212 |
+
<td>
|
213 |
+
<nobr><?php fs_esc_html_echo_inline( 'Owner ID', 'owner-id', $slug ) ?>:</nobr>
|
214 |
+
</td>
|
215 |
+
<td colspan="2"><code><?php echo $user->id ?></code></td>
|
216 |
+
</tr>
|
217 |
+
<?php $row_index ++ ?>
|
218 |
+
<!--/ User ID -->
|
219 |
+
<?php endif ?>
|
220 |
+
<?php endif ?>
|
221 |
+
|
222 |
+
<!-- Public Key -->
|
223 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
224 |
+
echo ' class="alternate"';
|
225 |
+
} ?>>
|
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 -->
|
233 |
+
|
234 |
+
<!-- Secret Key -->
|
235 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
236 |
+
echo ' class="alternate"';
|
237 |
+
} ?>>
|
238 |
+
<td>
|
239 |
+
<nobr><?php fs_esc_html_echo_inline( 'Secret Key', 'secret-key', $slug ) ?>:</nobr>
|
240 |
+
</td>
|
241 |
+
<td>
|
242 |
+
<code><?php echo FS_Plugin_License::mask_secret_key_for_html( $install->secret_key ) ?></code>
|
243 |
+
<?php if ( ! $is_whitelabeled ) : ?>
|
244 |
+
<input type="text" value="<?php echo htmlspecialchars( $install->secret_key ) ?>"
|
245 |
+
style="display: none" readonly/></td>
|
246 |
+
<?php endif ?>
|
247 |
+
<?php if ( ! $is_whitelabeled ) : ?>
|
248 |
+
<td><button class="button button-small fs-toggle-visibility"><?php fs_esc_html_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?></button></td>
|
249 |
+
<?php endif ?>
|
250 |
+
</tr>
|
251 |
+
<?php $row_index ++ ?>
|
252 |
+
<!--/ Secret Key -->
|
253 |
+
|
254 |
+
<?php if ( is_object( $license ) ) : ?>
|
255 |
+
<!-- License Key -->
|
256 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
257 |
+
echo ' class="alternate"';
|
258 |
+
} ?>>
|
259 |
+
<td>
|
260 |
+
<nobr><?php fs_esc_html_echo_inline( 'License Key', 'license-key', $slug ) ?>:</nobr>
|
261 |
+
</td>
|
262 |
+
<td>
|
263 |
+
<code><?php echo $license->get_html_escaped_masked_secret_key() ?></code>
|
264 |
+
<?php if ( ! $is_whitelabeled ) : ?>
|
265 |
+
<input type="text" value="<?php echo htmlspecialchars( $license->secret_key ) ?>"
|
266 |
+
style="display: none" readonly/></td>
|
267 |
+
<?php endif ?>
|
268 |
+
<?php if ( ! $is_whitelabeled ) : ?>
|
269 |
+
<td>
|
270 |
+
<button class="button button-small fs-toggle-visibility"><?php fs_esc_html_echo_x_inline( 'Show', 'verb', 'show', $slug ) ?></button>
|
271 |
+
<button class="button button-small activate-license-trigger <?php echo $fs->get_unique_affix() ?>"><?php fs_esc_html_echo_inline( 'Change License', 'change-license', $slug ) ?></button>
|
272 |
+
</td>
|
273 |
+
<?php endif ?>
|
274 |
+
</tr>
|
275 |
+
<?php $row_index ++ ?>
|
276 |
+
<!--/ License Key -->
|
277 |
+
|
278 |
+
<?php if ( ! is_object( $main_license ) || $main_license->id != $license->id ) : ?>
|
279 |
+
<?php $subscription = $fs->_get_subscription( $license->id ) ?>
|
280 |
+
<?php if ( ! $license->is_lifetime() && is_object( $subscription ) ) : ?>
|
281 |
+
<!-- Subscription -->
|
282 |
+
<tr <?php if ( 1 == $row_index % 2 ) {
|
283 |
+
echo ' class="alternate"';
|
284 |
+
} ?>>
|
285 |
+
<td>
|
286 |
+
<nobr><?php fs_esc_html_echo_inline( 'Subscription', 'subscription', $slug ) ?>:</nobr>
|
287 |
+
</td>
|
288 |
+
<?php
|
289 |
+
$is_active_subscription = $subscription->is_active();
|
290 |
+
|
291 |
+
$renews_in_text = fs_text_inline( 'Auto renews in %s', 'renews-in', $slug );
|
292 |
+
/* translators: %s: Time period (e.g. Expires in "2 months") */
|
293 |
+
$expires_in_text = fs_text_inline( 'Expires in %s', 'expires-in', $slug );
|
294 |
+
?>
|
295 |
+
<td>
|
296 |
+
<code><?php echo $subscription->id ?> - <?php
|
297 |
+
echo ( 12 == $subscription->billing_cycle ?
|
298 |
+
_fs_text_inline( 'Annual', 'annual', $slug ) :
|
299 |
+
_fs_text_inline( 'Monthly', 'monthly', $slug )
|
300 |
+
);
|
301 |
+
?>
|
302 |
+
</code>
|
303 |
+
<?php if ( ! $is_active_subscription && ! $license->is_first_payment_pending() ) : ?>
|
304 |
+
<label class="fs-tag fs-warn"><?php echo esc_html( sprintf( $expires_in_text, human_time_diff( time(), strtotime( $license->expiration ) ) ) ) ?></label>
|
305 |
+
<?php elseif ( $is_active_subscription && ! $subscription->is_first_payment_pending() ) : ?>
|
306 |
+
<label class="fs-tag fs-success"><?php echo esc_html( sprintf( $renews_in_text, human_time_diff( time(), strtotime( $subscription->next_payment ) ) ) ) ?></label>
|
307 |
+
<?php endif ?>
|
308 |
+
</td>
|
309 |
+
<td><?php if ( $is_active_subscription ) : ?>
|
310 |
+
<?php
|
311 |
+
$downgrading_plan_text = fs_text_inline( 'Downgrading your plan', 'downgrading-plan', $slug );
|
312 |
+
$cancelling_subscription_text = fs_text_inline( 'Cancelling the subscription', 'cancelling-subscription', $slug );
|
313 |
+
/* translators: %1$s: Either 'Downgrading your plan' or 'Cancelling the subscription' */
|
314 |
+
$downgrade_x_confirm_text = fs_text_inline( '%1$s will immediately stop all future recurring payments and your %2$s plan license will expire in %3$s.', 'downgrade-x-confirm', $slug );
|
315 |
+
$prices_increase_text = fs_text_inline( '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.', 'pricing-increase-warning', $slug );
|
316 |
+
$after_downgrade_non_blocking_text = fs_text_inline( 'You can still enjoy all %s features but you will not have access to %s security & feature updates, nor support.', 'after-downgrade-non-blocking', $slug );
|
317 |
+
$after_downgrade_blocking_text = fs_text_inline( 'Once your license expires you can still use the Free version but you will NOT have access to the %s features.', 'after-downgrade-blocking', $slug );
|
318 |
+
$downgrade_text = fs_text_x_inline( 'Downgrade', 'verb', 'downgrade', $slug );
|
319 |
+
|
320 |
+
$human_readable_license_expiration = human_time_diff( time(), strtotime( $license->expiration ) );
|
321 |
+
$downgrade_confirmation_message = sprintf(
|
322 |
+
$downgrade_x_confirm_text,
|
323 |
+
( $fs->is_only_premium() ? $cancelling_subscription_text : $downgrading_plan_text ),
|
324 |
+
$plan->title,
|
325 |
+
$human_readable_license_expiration
|
326 |
+
);
|
327 |
+
|
328 |
+
$after_downgrade_message = ! $license->is_block_features ?
|
329 |
+
sprintf( $after_downgrade_non_blocking_text, $plan->title, $fs->get_module_label( true ) ) :
|
330 |
+
sprintf( $after_downgrade_blocking_text, $plan->title );
|
331 |
+
?>
|
332 |
+
<?php $action = 'downgrade_account' ?>
|
333 |
+
<form id="fs_downgrade" action="<?php echo $fs->_get_admin_page_url( 'account' ) ?>" method="POST">
|
334 |
+
<input type="hidden" name="fs_action" value="<?php echo $action ?>">
|
335 |
+
<?php wp_nonce_field( trim( "{$action}:{$blog_id}", ':' ) ) ?>
|
336 |
+
<input type="hidden" name="blog_id" value="<?php echo $blog_id ?>">
|
337 |
+
<button class="button button-small" onclick="if (confirm('<?php echo esc_attr( $downgrade_confirmation_message . ' ' . $after_downgrade_message . ' ' . $prices_increase_text ) ?>')) { this.parentNode.submit(); } else { return false; }"><?php echo $downgrade_text ?></button>
|
338 |
+
</form>
|
339 |
+
<?php endif ?></td>
|
340 |
+
</tr>
|
341 |
+
<?php $row_index ++ ?>
|
342 |
+
<?php endif ?>
|
343 |
+
<!--/ Subscription -->
|
344 |
+
<?php endif ?>
|
345 |
+
<?php endif ?>
|
346 |
+
|
347 |
+
</tbody>
|
348 |
+
</table>
|
349 |
+
</td>
|
350 |
+
</tr>
|
351 |
+
<!--/ More details -->
|
352 |
<?php endif ?>
|
freemius/templates/add-ons.php
CHANGED
@@ -1,502 +1,502 @@
|
|
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 1.0.3
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var array $VARS
|
15 |
-
* @var Freemius
|
16 |
-
*/
|
17 |
-
$fs = freemius( $VARS['id'] );
|
18 |
-
|
19 |
-
$slug = $fs->get_slug();
|
20 |
-
|
21 |
-
$open_addon_slug = fs_request_get( 'slug' );
|
22 |
-
|
23 |
-
$open_addon = false;
|
24 |
-
|
25 |
-
$is_data_debug_mode = $fs->is_data_debug_mode();
|
26 |
-
$is_whitelabeled = $fs->is_whitelabeled();
|
27 |
-
|
28 |
-
/**
|
29 |
-
* @var FS_Plugin[]
|
30 |
-
*/
|
31 |
-
$addons = $fs->get_addons();
|
32 |
-
|
33 |
-
$has_addons = ( is_array( $addons ) && 0 < count( $addons ) );
|
34 |
-
|
35 |
-
$account_addon_ids = $fs->get_updated_account_addons();
|
36 |
-
|
37 |
-
$download_latest_text = fs_text_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $slug );
|
38 |
-
$view_details_text = fs_text_inline( 'View details', 'view-details', $slug );
|
39 |
-
|
40 |
-
$has_tabs = $fs->_add_tabs_before_content();
|
41 |
-
|
42 |
-
$fs_blog_id = ( is_multisite() && ! is_network_admin() ) ?
|
43 |
-
get_current_blog_id() :
|
44 |
-
0;
|
45 |
-
?>
|
46 |
-
<div id="fs_addons" class="wrap fs-section">
|
47 |
-
<?php if ( ! $has_tabs ) : ?>
|
48 |
-
<h2><?php echo esc_html( sprintf( fs_text_inline( 'Add Ons for %s', 'add-ons-for-x', $slug ), $fs->get_plugin_name() ) ) ?></h2>
|
49 |
-
<?php endif ?>
|
50 |
-
|
51 |
-
<?php $fs->do_action( 'addons/after_title' ) ?>
|
52 |
-
|
53 |
-
<div id="poststuff">
|
54 |
-
<?php if ( ! $has_addons ) : ?>
|
55 |
-
<h3><?php echo esc_html( sprintf(
|
56 |
-
'%s... %s',
|
57 |
-
fs_text_x_inline( 'Oops', 'exclamation', 'oops', $slug ),
|
58 |
-
fs_text_inline( 'We couldn\'t load the add-ons list. It\'s probably an issue on our side, please try to come back in few minutes.', 'add-ons-missing', $slug )
|
59 |
-
) ) ?></h3>
|
60 |
-
<?php endif ?>
|
61 |
-
<ul class="fs-cards-list">
|
62 |
-
<?php if ( $has_addons ) : ?>
|
63 |
-
<?php
|
64 |
-
$plans_and_pricing_by_addon_id = $fs->_get_addons_plans_and_pricing_map_by_id();
|
65 |
-
|
66 |
-
$active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $fs_blog_id );
|
67 |
-
?>
|
68 |
-
<?php
|
69 |
-
$hide_all_addons_data = false;
|
70 |
-
|
71 |
-
if ( $fs->is_whitelabeled_by_flag() ) {
|
72 |
-
$hide_all_addons_data = true;
|
73 |
-
|
74 |
-
$addon_ids = $fs->get_updated_account_addons();
|
75 |
-
$installed_addons = $fs->get_installed_addons();
|
76 |
-
foreach ( $installed_addons as $fs_addon ) {
|
77 |
-
$addon_ids[] = $fs_addon->get_id();
|
78 |
-
}
|
79 |
-
|
80 |
-
if ( ! empty( $addon_ids ) ) {
|
81 |
-
$addon_ids = array_unique( $addon_ids );
|
82 |
-
}
|
83 |
-
|
84 |
-
foreach ( $addon_ids as $addon_id ) {
|
85 |
-
$addon = $fs->get_addon( $addon_id );
|
86 |
-
|
87 |
-
if ( ! is_object( $addon ) ) {
|
88 |
-
continue;
|
89 |
-
}
|
90 |
-
|
91 |
-
$addon_storage = FS_Storage::instance( WP_FS__MODULE_TYPE_PLUGIN, $addon->slug );
|
92 |
-
|
93 |
-
if ( ! $addon_storage->is_whitelabeled ) {
|
94 |
-
$hide_all_addons_data = false;
|
95 |
-
break;
|
96 |
-
}
|
97 |
-
|
98 |
-
if ( $is_data_debug_mode ) {
|
99 |
-
$is_whitelabeled = false;
|
100 |
-
}
|
101 |
-
}
|
102 |
-
}
|
103 |
-
?>
|
104 |
-
<?php foreach ( $addons as $addon ) : ?>
|
105 |
-
<?php
|
106 |
-
$basename = $fs->get_addon_basename( $addon->id );
|
107 |
-
|
108 |
-
$is_addon_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $basename ) );
|
109 |
-
|
110 |
-
if ( ! $is_addon_installed && $hide_all_addons_data ) {
|
111 |
-
continue;
|
112 |
-
}
|
113 |
-
|
114 |
-
$is_addon_activated = $is_addon_installed ?
|
115 |
-
$fs->is_addon_activated( $addon->id ) :
|
116 |
-
false;
|
117 |
-
|
118 |
-
$is_plugin_active = (
|
119 |
-
$is_addon_activated ||
|
120 |
-
isset( $active_plugins_directories_map[ dirname( $basename ) ] )
|
121 |
-
);
|
122 |
-
|
123 |
-
$open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
|
124 |
-
|
125 |
-
$price = 0;
|
126 |
-
$has_trial = false;
|
127 |
-
$has_free_plan = false;
|
128 |
-
$has_paid_plan = false;
|
129 |
-
|
130 |
-
if ( isset( $plans_and_pricing_by_addon_id[$addon->id] ) ) {
|
131 |
-
$plans = $plans_and_pricing_by_addon_id[$addon->id];
|
132 |
-
|
133 |
-
if ( is_array( $plans ) && 0 < count( $plans ) ) {
|
134 |
-
foreach ( $plans as $plan ) {
|
135 |
-
if ( ! isset( $plan->pricing ) ||
|
136 |
-
! is_array( $plan->pricing ) ||
|
137 |
-
0 == count( $plan->pricing )
|
138 |
-
) {
|
139 |
-
// No pricing means a free plan.
|
140 |
-
$has_free_plan = true;
|
141 |
-
continue;
|
142 |
-
}
|
143 |
-
|
144 |
-
|
145 |
-
$has_paid_plan = true;
|
146 |
-
$has_trial = $has_trial || ( is_numeric( $plan->trial_period ) && ( $plan->trial_period > 0 ) );
|
147 |
-
|
148 |
-
$min_price = 999999;
|
149 |
-
foreach ( $plan->pricing as $pricing ) {
|
150 |
-
$pricing = new FS_Pricing( $pricing );
|
151 |
-
|
152 |
-
if ( ! $pricing->is_usd() ) {
|
153 |
-
/**
|
154 |
-
* Skip non-USD pricing.
|
155 |
-
*
|
156 |
-
* @author Leo Fajardo (@leorw)
|
157 |
-
* @since 2.3.1
|
158 |
-
*/
|
159 |
-
continue;
|
160 |
-
}
|
161 |
-
|
162 |
-
if ( $pricing->has_annual() ) {
|
163 |
-
$min_price = min( $min_price, $pricing->annual_price );
|
164 |
-
} else if ( $pricing->has_monthly() ) {
|
165 |
-
$min_price = min( $min_price, 12 * $pricing->monthly_price );
|
166 |
-
}
|
167 |
-
}
|
168 |
-
|
169 |
-
if ( $min_price < 999999 ) {
|
170 |
-
$price = $min_price;
|
171 |
-
}
|
172 |
-
|
173 |
-
}
|
174 |
-
}
|
175 |
-
|
176 |
-
if ( ! $has_paid_plan && ! $has_free_plan ) {
|
177 |
-
continue;
|
178 |
-
}
|
179 |
-
}
|
180 |
-
?>
|
181 |
-
<li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
|
182 |
-
<?php
|
183 |
-
$view_details_link = sprintf( '<a href="%s" aria-label="%s" data-title="%s"',
|
184 |
-
esc_url( network_admin_url( 'plugin-install.php?fs_allow_updater_and_dialog=true' . ( ! empty( $fs_blog_id ) ? '&fs_blog_id=' . $fs_blog_id : '' ) . '&tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
|
185 |
-
'&TB_iframe=true&width=600&height=550' ) ),
|
186 |
-
esc_attr( sprintf( fs_text_inline( 'More information about %s', 'more-information-about-x', $slug ), $addon->title ) ),
|
187 |
-
esc_attr( $addon->title )
|
188 |
-
) . ' class="thickbox%s">%s</a>';
|
189 |
-
|
190 |
-
echo sprintf(
|
191 |
-
$view_details_link,
|
192 |
-
/**
|
193 |
-
* Additional class.
|
194 |
-
*
|
195 |
-
* @author Leo Fajardo (@leorw)
|
196 |
-
* @since 2.2.4
|
197 |
-
*/
|
198 |
-
' fs-overlay',
|
199 |
-
/**
|
200 |
-
* Set the view details link text to an empty string since it is an overlay that
|
201 |
-
* doesn't really need a text and whose purpose is to open the details dialog when
|
202 |
-
* the card is clicked.
|
203 |
-
*
|
204 |
-
* @author Leo Fajardo (@leorw)
|
205 |
-
* @since 2.2.4
|
206 |
-
*/
|
207 |
-
''
|
208 |
-
);
|
209 |
-
?>
|
210 |
-
<?php
|
211 |
-
if ( is_null( $addon->info ) ) {
|
212 |
-
$addon->info = new stdClass();
|
213 |
-
}
|
214 |
-
if ( ! isset( $addon->info->card_banner_url ) ) {
|
215 |
-
$addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
|
216 |
-
}
|
217 |
-
if ( ! isset( $addon->info->short_description ) ) {
|
218 |
-
$addon->info->short_description = 'What\'s the one thing your add-on does really, really well?';
|
219 |
-
}
|
220 |
-
?>
|
221 |
-
<div class="fs-inner">
|
222 |
-
<ul>
|
223 |
-
<li class="fs-card-banner"
|
224 |
-
style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"><?php
|
225 |
-
if ( $is_plugin_active || $is_addon_installed ) {
|
226 |
-
echo sprintf(
|
227 |
-
'<span class="fs-badge fs-installed-addon-badge">%s</span>',
|
228 |
-
esc_html( $is_plugin_active ?
|
229 |
-
fs_text_x_inline( 'Active', 'active add-on', 'active-addon', $slug ) :
|
230 |
-
fs_text_x_inline( 'Installed', 'installed add-on', 'installed-addon', $slug )
|
231 |
-
)
|
232 |
-
);
|
233 |
-
}
|
234 |
-
?></li>
|
235 |
-
<!-- <li class="fs-tag"></li> -->
|
236 |
-
<li class="fs-title"><?php echo $addon->title ?></li>
|
237 |
-
<li class="fs-offer">
|
238 |
-
<span
|
239 |
-
class="fs-price"><?php
|
240 |
-
if ( $is_whitelabeled ) {
|
241 |
-
echo ' ';
|
242 |
-
} else {
|
243 |
-
$descriptors = array();
|
244 |
-
|
245 |
-
if ($has_free_plan)
|
246 |
-
$descriptors[] = fs_text_inline( 'Free', 'free', $slug );
|
247 |
-
if ($has_paid_plan && $price > 0)
|
248 |
-
$descriptors[] = '$' . number_format( $price, 2 );
|
249 |
-
if ($has_trial)
|
250 |
-
$descriptors[] = fs_text_x_inline( 'Trial', 'trial period', 'trial', $slug );
|
251 |
-
|
252 |
-
echo implode(' - ', $descriptors);
|
253 |
-
|
254 |
-
} ?></span>
|
255 |
-
</li>
|
256 |
-
<li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
|
257 |
-
<?php
|
258 |
-
$is_free_only_wp_org_compliant = ( ! $has_paid_plan && $addon->is_wp_org_compliant );
|
259 |
-
|
260 |
-
$is_allowed_to_install = (
|
261 |
-
$fs->is_allowed_to_install() ||
|
262 |
-
$is_free_only_wp_org_compliant
|
263 |
-
);
|
264 |
-
|
265 |
-
$show_premium_activation_or_installation_action = true;
|
266 |
-
|
267 |
-
if ( ! in_array( $addon->id, $account_addon_ids ) ) {
|
268 |
-
$show_premium_activation_or_installation_action = false;
|
269 |
-
} else if ( $is_addon_installed ) {
|
270 |
-
/**
|
271 |
-
* If any add-on's version (free or premium) is installed, check if the
|
272 |
-
* premium version can be activated and show the relevant action. Otherwise,
|
273 |
-
* show the relevant action for the free version.
|
274 |
-
*
|
275 |
-
* @author Leo Fajardo (@leorw)
|
276 |
-
* @since 2.4.5
|
277 |
-
*/
|
278 |
-
$fs_addon = $is_addon_activated ?
|
279 |
-
$fs->get_addon_instance( $addon->id ) :
|
280 |
-
null;
|
281 |
-
|
282 |
-
$premium_plugin_basename = is_object( $fs_addon ) ?
|
283 |
-
$fs_addon->premium_plugin_basename() :
|
284 |
-
"{$addon->premium_slug}/{$addon->slug}.php";
|
285 |
-
|
286 |
-
if (
|
287 |
-
( $is_addon_activated && $fs_addon->is_premium() ) ||
|
288 |
-
file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_plugin_basename ) )
|
289 |
-
) {
|
290 |
-
$basename = $premium_plugin_basename;
|
291 |
-
}
|
292 |
-
|
293 |
-
$show_premium_activation_or_installation_action = (
|
294 |
-
( ! $is_addon_activated || ! $fs_addon->is_premium() ) &&
|
295 |
-
/**
|
296 |
-
* This check is needed for cases when an active add-on doesn't have an
|
297 |
-
* associated Freemius instance.
|
298 |
-
*
|
299 |
-
* @author Leo Fajardo (@leorw)
|
300 |
-
* @since 2.4.5
|
301 |
-
*/
|
302 |
-
( ! $is_plugin_active )
|
303 |
-
);
|
304 |
-
}
|
305 |
-
?>
|
306 |
-
<?php if ( ! $show_premium_activation_or_installation_action ) : ?>
|
307 |
-
<li class="fs-cta"><a class="button"><?php echo esc_html( $view_details_text ) ?></a></li>
|
308 |
-
<?php else : ?>
|
309 |
-
<?php
|
310 |
-
$latest_download_local_url = $is_free_only_wp_org_compliant ?
|
311 |
-
null :
|
312 |
-
$fs->_get_latest_download_local_url( $addon->id );
|
313 |
-
?>
|
314 |
-
|
315 |
-
<li class="fs-cta fs-dropdown">
|
316 |
-
<div class="button-group">
|
317 |
-
<?php if ( $is_allowed_to_install ) : ?>
|
318 |
-
<?php
|
319 |
-
if ( ! $is_addon_installed ) {
|
320 |
-
echo sprintf(
|
321 |
-
'<a class="button button-primary" href="%s">%s</a>',
|
322 |
-
wp_nonce_url( self_admin_url( 'update.php?' . ( ( $has_paid_plan || ! $addon->is_wp_org_compliant ) ? 'fs_allow_updater_and_dialog=true&' : '' ) . 'action=install-plugin&plugin=' . $addon->slug ), 'install-plugin_' . $addon->slug ),
|
323 |
-
fs_esc_html_inline( 'Install Now', 'install-now', $slug )
|
324 |
-
);
|
325 |
-
} else {
|
326 |
-
echo sprintf(
|
327 |
-
'<a class="button button-primary edit" href="%s" title="%s" target="_parent">%s</a>',
|
328 |
-
wp_nonce_url( 'plugins.php?action=activate&plugin=' . $basename, 'activate-plugin_' . $basename ),
|
329 |
-
fs_esc_attr_inline( 'Activate this add-on', 'activate-this-addon', $addon->slug ),
|
330 |
-
fs_text_inline( 'Activate', 'activate', $addon->slug )
|
331 |
-
);
|
332 |
-
}
|
333 |
-
?>
|
334 |
-
<?php else : ?>
|
335 |
-
<a target="_blank" rel="noopener" class="button button-primary" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a>
|
336 |
-
<?php endif ?>
|
337 |
-
<div class="button button-primary fs-dropdown-arrow-button"><span class="fs-dropdown-arrow"></span><ul class="fs-dropdown-list" style="display: none">
|
338 |
-
<?php if ( $is_allowed_to_install && ! empty( $latest_download_local_url ) ) : ?>
|
339 |
-
<li><a target="_blank" rel="noopener" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a></li>
|
340 |
-
<?php endif ?>
|
341 |
-
<li><?php
|
342 |
-
echo sprintf(
|
343 |
-
$view_details_link,
|
344 |
-
/**
|
345 |
-
* No additional class.
|
346 |
-
*
|
347 |
-
* @author Leo Fajardo (@leorw)
|
348 |
-
* @since 2.2.4
|
349 |
-
*/
|
350 |
-
'',
|
351 |
-
/**
|
352 |
-
* Set the view details link text to a non-empty string since it is an
|
353 |
-
* item in the dropdown list and the text should be visible.
|
354 |
-
*
|
355 |
-
* @author Leo Fajardo (@leorw)
|
356 |
-
* @since 2.2.4
|
357 |
-
*/
|
358 |
-
esc_html( $view_details_text )
|
359 |
-
);
|
360 |
-
?></li>
|
361 |
-
</ul></div>
|
362 |
-
</div>
|
363 |
-
</li>
|
364 |
-
<?php endif ?>
|
365 |
-
</ul>
|
366 |
-
</div>
|
367 |
-
</li>
|
368 |
-
<?php endforeach ?>
|
369 |
-
<?php endif ?>
|
370 |
-
</ul>
|
371 |
-
</div>
|
372 |
-
|
373 |
-
<?php $fs->do_action( 'addons/after_addons' ) ?>
|
374 |
-
</div>
|
375 |
-
<script type="text/javascript">
|
376 |
-
(function( $, undef ) {
|
377 |
-
<?php if ( $open_addon ) : ?>
|
378 |
-
|
379 |
-
var interval = setInterval(function () {
|
380 |
-
// Open add-on information page.
|
381 |
-
<?php
|
382 |
-
/**
|
383 |
-
* @author Vova Feldman
|
384 |
-
*
|
385 |
-
* This code does NOT expose an XSS vulnerability because:
|
386 |
-
* 1. This page only renders for admins, so if an attacker manage to get
|
387 |
-
* admin access, they can do more harm.
|
388 |
-
* 2. This code won't be rendered unless $open_addon_slug matches any of
|
389 |
-
* the plugin's add-ons slugs.
|
390 |
-
*/
|
391 |
-
?>
|
392 |
-
$('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
|
393 |
-
if ($('#TB_iframeContent').length > 0) {
|
394 |
-
clearInterval(interval);
|
395 |
-
interval = null;
|
396 |
-
}
|
397 |
-
}, 200);
|
398 |
-
|
399 |
-
<?php else : ?>
|
400 |
-
|
401 |
-
$( '.fs-card.fs-addon' )
|
402 |
-
.mouseover(function() {
|
403 |
-
var $this = $( this );
|
404 |
-
|
405 |
-
$this.find( '.fs-cta .button' ).addClass( 'button-primary' );
|
406 |
-
|
407 |
-
if ( 0 === $this.find( '.fs-dropdown-arrow-button.active' ).length ) {
|
408 |
-
/**
|
409 |
-
* When hovering over a card, close the dropdown on any other card.
|
410 |
-
*
|
411 |
-
* @author Leo Fajardo (@leorw)
|
412 |
-
* @since 2.2.4
|
413 |
-
*/
|
414 |
-
toggleDropdown();
|
415 |
-
}
|
416 |
-
}).mouseout(function( evt ) {
|
417 |
-
var $relatedTarget = $( evt.relatedTarget );
|
418 |
-
|
419 |
-
if ( 0 !== $relatedTarget.parents( '.fs-addon' ).length ) {
|
420 |
-
return true;
|
421 |
-
}
|
422 |
-
|
423 |
-
var $this = $( this );
|
424 |
-
|
425 |
-
/**
|
426 |
-
* Set the color of the "View details" button to "secondary".
|
427 |
-
*
|
428 |
-
* @author Leo Fajardo (@leorw)
|
429 |
-
* @since 2.2.4
|
430 |
-
*/
|
431 |
-
$this.find( '.fs-cta .button' ).filter(function() {
|
432 |
-
/**
|
433 |
-
* Keep the "primary" color of the dropdown arrow button, "Install Now" button, and
|
434 |
-
* "Download Latest" button.
|
435 |
-
|
436 |
-
* @author Leo Fajardo (@leorw)
|
437 |
-
* @since 2.2.4
|
438 |
-
*/
|
439 |
-
return $( this ).parent().is( ':not(.button-group)' );
|
440 |
-
}).removeClass('button-primary');
|
441 |
-
|
442 |
-
toggleDropdown( $this.find( '.fs-dropdown' ), false );
|
443 |
-
}).find( 'a.thickbox, .button:not(.fs-dropdown-arrow-button)' ).click(function() {
|
444 |
-
toggleDropdown();
|
445 |
-
});
|
446 |
-
|
447 |
-
<?php endif ?>
|
448 |
-
|
449 |
-
var $dropdowns = $( '.fs-dropdown' );
|
450 |
-
if ( 0 !== $dropdowns.length ) {
|
451 |
-
$dropdowns.find( '.fs-dropdown-arrow-button' ).click(function() {
|
452 |
-
var $this = $( this ),
|
453 |
-
$dropdown = $this.parents( '.fs-dropdown' );
|
454 |
-
|
455 |
-
toggleDropdown( $dropdown, ! $dropdown.hasClass( 'active' ) );
|
456 |
-
});
|
457 |
-
}
|
458 |
-
|
459 |
-
/**
|
460 |
-
* Returns the default state of the dropdown arrow button and hides the dropdown list.
|
461 |
-
*
|
462 |
-
* @author Leo Fajardo (@leorw)
|
463 |
-
* @since 2.2.4
|
464 |
-
*
|
465 |
-
* @param {(Object|undefined)} [$dropdown]
|
466 |
-
* @param {(Boolean|undefined)} [state]
|
467 |
-
*/
|
468 |
-
function toggleDropdown( $dropdown, state ) {
|
469 |
-
if ( undef === $dropdown ) {
|
470 |
-
var $activeDropdown = $dropdowns.find( '.active' );
|
471 |
-
if ( 0 !== $activeDropdown.length ) {
|
472 |
-
$dropdown = $activeDropdown;
|
473 |
-
}
|
474 |
-
}
|
475 |
-
|
476 |
-
if ( undef === $dropdown ) {
|
477 |
-
return;
|
478 |
-
}
|
479 |
-
|
480 |
-
if ( undef === state ) {
|
481 |
-
state = false;
|
482 |
-
}
|
483 |
-
|
484 |
-
$dropdown.toggleClass( 'active', state );
|
485 |
-
$dropdown.find( '.fs-dropdown-list' ).toggle( state );
|
486 |
-
$dropdown.find( '.fs-dropdown-arrow-button' ).toggleClass( 'active', state );
|
487 |
-
}
|
488 |
-
})( jQuery );
|
489 |
-
</script>
|
490 |
-
<?php
|
491 |
-
if ( $has_tabs ) {
|
492 |
-
$fs->_add_tabs_after_content();
|
493 |
-
}
|
494 |
-
|
495 |
-
$params = array(
|
496 |
-
'page' => 'addons',
|
497 |
-
'module_id' => $fs->get_id(),
|
498 |
-
'module_type' => $fs->get_module_type(),
|
499 |
-
'module_slug' => $slug,
|
500 |
-
'module_version' => $fs->get_plugin_version(),
|
501 |
-
);
|
502 |
fs_require_template( 'powered-by.php', $params );
|
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 1.0.3
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var array $VARS
|
15 |
+
* @var Freemius
|
16 |
+
*/
|
17 |
+
$fs = freemius( $VARS['id'] );
|
18 |
+
|
19 |
+
$slug = $fs->get_slug();
|
20 |
+
|
21 |
+
$open_addon_slug = fs_request_get( 'slug' );
|
22 |
+
|
23 |
+
$open_addon = false;
|
24 |
+
|
25 |
+
$is_data_debug_mode = $fs->is_data_debug_mode();
|
26 |
+
$is_whitelabeled = $fs->is_whitelabeled();
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var FS_Plugin[]
|
30 |
+
*/
|
31 |
+
$addons = $fs->get_addons();
|
32 |
+
|
33 |
+
$has_addons = ( is_array( $addons ) && 0 < count( $addons ) );
|
34 |
+
|
35 |
+
$account_addon_ids = $fs->get_updated_account_addons();
|
36 |
+
|
37 |
+
$download_latest_text = fs_text_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $slug );
|
38 |
+
$view_details_text = fs_text_inline( 'View details', 'view-details', $slug );
|
39 |
+
|
40 |
+
$has_tabs = $fs->_add_tabs_before_content();
|
41 |
+
|
42 |
+
$fs_blog_id = ( is_multisite() && ! is_network_admin() ) ?
|
43 |
+
get_current_blog_id() :
|
44 |
+
0;
|
45 |
+
?>
|
46 |
+
<div id="fs_addons" class="wrap fs-section">
|
47 |
+
<?php if ( ! $has_tabs ) : ?>
|
48 |
+
<h2><?php echo esc_html( sprintf( fs_text_inline( 'Add Ons for %s', 'add-ons-for-x', $slug ), $fs->get_plugin_name() ) ) ?></h2>
|
49 |
+
<?php endif ?>
|
50 |
+
|
51 |
+
<?php $fs->do_action( 'addons/after_title' ) ?>
|
52 |
+
|
53 |
+
<div id="poststuff">
|
54 |
+
<?php if ( ! $has_addons ) : ?>
|
55 |
+
<h3><?php echo esc_html( sprintf(
|
56 |
+
'%s... %s',
|
57 |
+
fs_text_x_inline( 'Oops', 'exclamation', 'oops', $slug ),
|
58 |
+
fs_text_inline( 'We couldn\'t load the add-ons list. It\'s probably an issue on our side, please try to come back in few minutes.', 'add-ons-missing', $slug )
|
59 |
+
) ) ?></h3>
|
60 |
+
<?php endif ?>
|
61 |
+
<ul class="fs-cards-list">
|
62 |
+
<?php if ( $has_addons ) : ?>
|
63 |
+
<?php
|
64 |
+
$plans_and_pricing_by_addon_id = $fs->_get_addons_plans_and_pricing_map_by_id();
|
65 |
+
|
66 |
+
$active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $fs_blog_id );
|
67 |
+
?>
|
68 |
+
<?php
|
69 |
+
$hide_all_addons_data = false;
|
70 |
+
|
71 |
+
if ( $fs->is_whitelabeled_by_flag() ) {
|
72 |
+
$hide_all_addons_data = true;
|
73 |
+
|
74 |
+
$addon_ids = $fs->get_updated_account_addons();
|
75 |
+
$installed_addons = $fs->get_installed_addons();
|
76 |
+
foreach ( $installed_addons as $fs_addon ) {
|
77 |
+
$addon_ids[] = $fs_addon->get_id();
|
78 |
+
}
|
79 |
+
|
80 |
+
if ( ! empty( $addon_ids ) ) {
|
81 |
+
$addon_ids = array_unique( $addon_ids );
|
82 |
+
}
|
83 |
+
|
84 |
+
foreach ( $addon_ids as $addon_id ) {
|
85 |
+
$addon = $fs->get_addon( $addon_id );
|
86 |
+
|
87 |
+
if ( ! is_object( $addon ) ) {
|
88 |
+
continue;
|
89 |
+
}
|
90 |
+
|
91 |
+
$addon_storage = FS_Storage::instance( WP_FS__MODULE_TYPE_PLUGIN, $addon->slug );
|
92 |
+
|
93 |
+
if ( ! $addon_storage->is_whitelabeled ) {
|
94 |
+
$hide_all_addons_data = false;
|
95 |
+
break;
|
96 |
+
}
|
97 |
+
|
98 |
+
if ( $is_data_debug_mode ) {
|
99 |
+
$is_whitelabeled = false;
|
100 |
+
}
|
101 |
+
}
|
102 |
+
}
|
103 |
+
?>
|
104 |
+
<?php foreach ( $addons as $addon ) : ?>
|
105 |
+
<?php
|
106 |
+
$basename = $fs->get_addon_basename( $addon->id );
|
107 |
+
|
108 |
+
$is_addon_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $basename ) );
|
109 |
+
|
110 |
+
if ( ! $is_addon_installed && $hide_all_addons_data ) {
|
111 |
+
continue;
|
112 |
+
}
|
113 |
+
|
114 |
+
$is_addon_activated = $is_addon_installed ?
|
115 |
+
$fs->is_addon_activated( $addon->id ) :
|
116 |
+
false;
|
117 |
+
|
118 |
+
$is_plugin_active = (
|
119 |
+
$is_addon_activated ||
|
120 |
+
isset( $active_plugins_directories_map[ dirname( $basename ) ] )
|
121 |
+
);
|
122 |
+
|
123 |
+
$open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
|
124 |
+
|
125 |
+
$price = 0;
|
126 |
+
$has_trial = false;
|
127 |
+
$has_free_plan = false;
|
128 |
+
$has_paid_plan = false;
|
129 |
+
|
130 |
+
if ( isset( $plans_and_pricing_by_addon_id[$addon->id] ) ) {
|
131 |
+
$plans = $plans_and_pricing_by_addon_id[$addon->id];
|
132 |
+
|
133 |
+
if ( is_array( $plans ) && 0 < count( $plans ) ) {
|
134 |
+
foreach ( $plans as $plan ) {
|
135 |
+
if ( ! isset( $plan->pricing ) ||
|
136 |
+
! is_array( $plan->pricing ) ||
|
137 |
+
0 == count( $plan->pricing )
|
138 |
+
) {
|
139 |
+
// No pricing means a free plan.
|
140 |
+
$has_free_plan = true;
|
141 |
+
continue;
|
142 |
+
}
|
143 |
+
|
144 |
+
|
145 |
+
$has_paid_plan = true;
|
146 |
+
$has_trial = $has_trial || ( is_numeric( $plan->trial_period ) && ( $plan->trial_period > 0 ) );
|
147 |
+
|
148 |
+
$min_price = 999999;
|
149 |
+
foreach ( $plan->pricing as $pricing ) {
|
150 |
+
$pricing = new FS_Pricing( $pricing );
|
151 |
+
|
152 |
+
if ( ! $pricing->is_usd() ) {
|
153 |
+
/**
|
154 |
+
* Skip non-USD pricing.
|
155 |
+
*
|
156 |
+
* @author Leo Fajardo (@leorw)
|
157 |
+
* @since 2.3.1
|
158 |
+
*/
|
159 |
+
continue;
|
160 |
+
}
|
161 |
+
|
162 |
+
if ( $pricing->has_annual() ) {
|
163 |
+
$min_price = min( $min_price, $pricing->annual_price );
|
164 |
+
} else if ( $pricing->has_monthly() ) {
|
165 |
+
$min_price = min( $min_price, 12 * $pricing->monthly_price );
|
166 |
+
}
|
167 |
+
}
|
168 |
+
|
169 |
+
if ( $min_price < 999999 ) {
|
170 |
+
$price = $min_price;
|
171 |
+
}
|
172 |
+
|
173 |
+
}
|
174 |
+
}
|
175 |
+
|
176 |
+
if ( ! $has_paid_plan && ! $has_free_plan ) {
|
177 |
+
continue;
|
178 |
+
}
|
179 |
+
}
|
180 |
+
?>
|
181 |
+
<li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
|
182 |
+
<?php
|
183 |
+
$view_details_link = sprintf( '<a href="%s" aria-label="%s" data-title="%s"',
|
184 |
+
esc_url( network_admin_url( 'plugin-install.php?fs_allow_updater_and_dialog=true' . ( ! empty( $fs_blog_id ) ? '&fs_blog_id=' . $fs_blog_id : '' ) . '&tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
|
185 |
+
'&TB_iframe=true&width=600&height=550' ) ),
|
186 |
+
esc_attr( sprintf( fs_text_inline( 'More information about %s', 'more-information-about-x', $slug ), $addon->title ) ),
|
187 |
+
esc_attr( $addon->title )
|
188 |
+
) . ' class="thickbox%s">%s</a>';
|
189 |
+
|
190 |
+
echo sprintf(
|
191 |
+
$view_details_link,
|
192 |
+
/**
|
193 |
+
* Additional class.
|
194 |
+
*
|
195 |
+
* @author Leo Fajardo (@leorw)
|
196 |
+
* @since 2.2.4
|
197 |
+
*/
|
198 |
+
' fs-overlay',
|
199 |
+
/**
|
200 |
+
* Set the view details link text to an empty string since it is an overlay that
|
201 |
+
* doesn't really need a text and whose purpose is to open the details dialog when
|
202 |
+
* the card is clicked.
|
203 |
+
*
|
204 |
+
* @author Leo Fajardo (@leorw)
|
205 |
+
* @since 2.2.4
|
206 |
+
*/
|
207 |
+
''
|
208 |
+
);
|
209 |
+
?>
|
210 |
+
<?php
|
211 |
+
if ( is_null( $addon->info ) ) {
|
212 |
+
$addon->info = new stdClass();
|
213 |
+
}
|
214 |
+
if ( ! isset( $addon->info->card_banner_url ) ) {
|
215 |
+
$addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
|
216 |
+
}
|
217 |
+
if ( ! isset( $addon->info->short_description ) ) {
|
218 |
+
$addon->info->short_description = 'What\'s the one thing your add-on does really, really well?';
|
219 |
+
}
|
220 |
+
?>
|
221 |
+
<div class="fs-inner">
|
222 |
+
<ul>
|
223 |
+
<li class="fs-card-banner"
|
224 |
+
style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"><?php
|
225 |
+
if ( $is_plugin_active || $is_addon_installed ) {
|
226 |
+
echo sprintf(
|
227 |
+
'<span class="fs-badge fs-installed-addon-badge">%s</span>',
|
228 |
+
esc_html( $is_plugin_active ?
|
229 |
+
fs_text_x_inline( 'Active', 'active add-on', 'active-addon', $slug ) :
|
230 |
+
fs_text_x_inline( 'Installed', 'installed add-on', 'installed-addon', $slug )
|
231 |
+
)
|
232 |
+
);
|
233 |
+
}
|
234 |
+
?></li>
|
235 |
+
<!-- <li class="fs-tag"></li> -->
|
236 |
+
<li class="fs-title"><?php echo $addon->title ?></li>
|
237 |
+
<li class="fs-offer">
|
238 |
+
<span
|
239 |
+
class="fs-price"><?php
|
240 |
+
if ( $is_whitelabeled ) {
|
241 |
+
echo ' ';
|
242 |
+
} else {
|
243 |
+
$descriptors = array();
|
244 |
+
|
245 |
+
if ($has_free_plan)
|
246 |
+
$descriptors[] = fs_text_inline( 'Free', 'free', $slug );
|
247 |
+
if ($has_paid_plan && $price > 0)
|
248 |
+
$descriptors[] = '$' . number_format( $price, 2 );
|
249 |
+
if ($has_trial)
|
250 |
+
$descriptors[] = fs_text_x_inline( 'Trial', 'trial period', 'trial', $slug );
|
251 |
+
|
252 |
+
echo implode(' - ', $descriptors);
|
253 |
+
|
254 |
+
} ?></span>
|
255 |
+
</li>
|
256 |
+
<li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
|
257 |
+
<?php
|
258 |
+
$is_free_only_wp_org_compliant = ( ! $has_paid_plan && $addon->is_wp_org_compliant );
|
259 |
+
|
260 |
+
$is_allowed_to_install = (
|
261 |
+
$fs->is_allowed_to_install() ||
|
262 |
+
$is_free_only_wp_org_compliant
|
263 |
+
);
|
264 |
+
|
265 |
+
$show_premium_activation_or_installation_action = true;
|
266 |
+
|
267 |
+
if ( ! in_array( $addon->id, $account_addon_ids ) ) {
|
268 |
+
$show_premium_activation_or_installation_action = false;
|
269 |
+
} else if ( $is_addon_installed ) {
|
270 |
+
/**
|
271 |
+
* If any add-on's version (free or premium) is installed, check if the
|
272 |
+
* premium version can be activated and show the relevant action. Otherwise,
|
273 |
+
* show the relevant action for the free version.
|
274 |
+
*
|
275 |
+
* @author Leo Fajardo (@leorw)
|
276 |
+
* @since 2.4.5
|
277 |
+
*/
|
278 |
+
$fs_addon = $is_addon_activated ?
|
279 |
+
$fs->get_addon_instance( $addon->id ) :
|
280 |
+
null;
|
281 |
+
|
282 |
+
$premium_plugin_basename = is_object( $fs_addon ) ?
|
283 |
+
$fs_addon->premium_plugin_basename() :
|
284 |
+
"{$addon->premium_slug}/{$addon->slug}.php";
|
285 |
+
|
286 |
+
if (
|
287 |
+
( $is_addon_activated && $fs_addon->is_premium() ) ||
|
288 |
+
file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_plugin_basename ) )
|
289 |
+
) {
|
290 |
+
$basename = $premium_plugin_basename;
|
291 |
+
}
|
292 |
+
|
293 |
+
$show_premium_activation_or_installation_action = (
|
294 |
+
( ! $is_addon_activated || ! $fs_addon->is_premium() ) &&
|
295 |
+
/**
|
296 |
+
* This check is needed for cases when an active add-on doesn't have an
|
297 |
+
* associated Freemius instance.
|
298 |
+
*
|
299 |
+
* @author Leo Fajardo (@leorw)
|
300 |
+
* @since 2.4.5
|
301 |
+
*/
|
302 |
+
( ! $is_plugin_active )
|
303 |
+
);
|
304 |
+
}
|
305 |
+
?>
|
306 |
+
<?php if ( ! $show_premium_activation_or_installation_action ) : ?>
|
307 |
+
<li class="fs-cta"><a class="button"><?php echo esc_html( $view_details_text ) ?></a></li>
|
308 |
+
<?php else : ?>
|
309 |
+
<?php
|
310 |
+
$latest_download_local_url = $is_free_only_wp_org_compliant ?
|
311 |
+
null :
|
312 |
+
$fs->_get_latest_download_local_url( $addon->id );
|
313 |
+
?>
|
314 |
+
|
315 |
+
<li class="fs-cta fs-dropdown">
|
316 |
+
<div class="button-group">
|
317 |
+
<?php if ( $is_allowed_to_install ) : ?>
|
318 |
+
<?php
|
319 |
+
if ( ! $is_addon_installed ) {
|
320 |
+
echo sprintf(
|
321 |
+
'<a class="button button-primary" href="%s">%s</a>',
|
322 |
+
wp_nonce_url( self_admin_url( 'update.php?' . ( ( $has_paid_plan || ! $addon->is_wp_org_compliant ) ? 'fs_allow_updater_and_dialog=true&' : '' ) . 'action=install-plugin&plugin=' . $addon->slug ), 'install-plugin_' . $addon->slug ),
|
323 |
+
fs_esc_html_inline( 'Install Now', 'install-now', $slug )
|
324 |
+
);
|
325 |
+
} else {
|
326 |
+
echo sprintf(
|
327 |
+
'<a class="button button-primary edit" href="%s" title="%s" target="_parent">%s</a>',
|
328 |
+
wp_nonce_url( 'plugins.php?action=activate&plugin=' . $basename, 'activate-plugin_' . $basename ),
|
329 |
+
fs_esc_attr_inline( 'Activate this add-on', 'activate-this-addon', $addon->slug ),
|
330 |
+
fs_text_inline( 'Activate', 'activate', $addon->slug )
|
331 |
+
);
|
332 |
+
}
|
333 |
+
?>
|
334 |
+
<?php else : ?>
|
335 |
+
<a target="_blank" rel="noopener" class="button button-primary" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a>
|
336 |
+
<?php endif ?>
|
337 |
+
<div class="button button-primary fs-dropdown-arrow-button"><span class="fs-dropdown-arrow"></span><ul class="fs-dropdown-list" style="display: none">
|
338 |
+
<?php if ( $is_allowed_to_install && ! empty( $latest_download_local_url ) ) : ?>
|
339 |
+
<li><a target="_blank" rel="noopener" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a></li>
|
340 |
+
<?php endif ?>
|
341 |
+
<li><?php
|
342 |
+
echo sprintf(
|
343 |
+
$view_details_link,
|
344 |
+
/**
|
345 |
+
* No additional class.
|
346 |
+
*
|
347 |
+
* @author Leo Fajardo (@leorw)
|
348 |
+
* @since 2.2.4
|
349 |
+
*/
|
350 |
+
'',
|
351 |
+
/**
|
352 |
+
* Set the view details link text to a non-empty string since it is an
|
353 |
+
* item in the dropdown list and the text should be visible.
|
354 |
+
*
|
355 |
+
* @author Leo Fajardo (@leorw)
|
356 |
+
* @since 2.2.4
|
357 |
+
*/
|
358 |
+
esc_html( $view_details_text )
|
359 |
+
);
|
360 |
+
?></li>
|
361 |
+
</ul></div>
|
362 |
+
</div>
|
363 |
+
</li>
|
364 |
+
<?php endif ?>
|
365 |
+
</ul>
|
366 |
+
</div>
|
367 |
+
</li>
|
368 |
+
<?php endforeach ?>
|
369 |
+
<?php endif ?>
|
370 |
+
</ul>
|
371 |
+
</div>
|
372 |
+
|
373 |
+
<?php $fs->do_action( 'addons/after_addons' ) ?>
|
374 |
+
</div>
|
375 |
+
<script type="text/javascript">
|
376 |
+
(function( $, undef ) {
|
377 |
+
<?php if ( $open_addon ) : ?>
|
378 |
+
|
379 |
+
var interval = setInterval(function () {
|
380 |
+
// Open add-on information page.
|
381 |
+
<?php
|
382 |
+
/**
|
383 |
+
* @author Vova Feldman
|
384 |
+
*
|
385 |
+
* This code does NOT expose an XSS vulnerability because:
|
386 |
+
* 1. This page only renders for admins, so if an attacker manage to get
|
387 |
+
* admin access, they can do more harm.
|
388 |
+
* 2. This code won't be rendered unless $open_addon_slug matches any of
|
389 |
+
* the plugin's add-ons slugs.
|
390 |
+
*/
|
391 |
+
?>
|
392 |
+
$('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
|
393 |
+
if ($('#TB_iframeContent').length > 0) {
|
394 |
+
clearInterval(interval);
|
395 |
+
interval = null;
|
396 |
+
}
|
397 |
+
}, 200);
|
398 |
+
|
399 |
+
<?php else : ?>
|
400 |
+
|
401 |
+
$( '.fs-card.fs-addon' )
|
402 |
+
.mouseover(function() {
|
403 |
+
var $this = $( this );
|
404 |
+
|
405 |
+
$this.find( '.fs-cta .button' ).addClass( 'button-primary' );
|
406 |
+
|
407 |
+
if ( 0 === $this.find( '.fs-dropdown-arrow-button.active' ).length ) {
|
408 |
+
/**
|
409 |
+
* When hovering over a card, close the dropdown on any other card.
|
410 |
+
*
|
411 |
+
* @author Leo Fajardo (@leorw)
|
412 |
+
* @since 2.2.4
|
413 |
+
*/
|
414 |
+
toggleDropdown();
|
415 |
+
}
|
416 |
+
}).mouseout(function( evt ) {
|
417 |
+
var $relatedTarget = $( evt.relatedTarget );
|
418 |
+
|
419 |
+
if ( 0 !== $relatedTarget.parents( '.fs-addon' ).length ) {
|
420 |
+
return true;
|
421 |
+
}
|
422 |
+
|
423 |
+
var $this = $( this );
|
424 |
+
|
425 |
+
/**
|
426 |
+
* Set the color of the "View details" button to "secondary".
|
427 |
+
*
|
428 |
+
* @author Leo Fajardo (@leorw)
|
429 |
+
* @since 2.2.4
|
430 |
+
*/
|
431 |
+
$this.find( '.fs-cta .button' ).filter(function() {
|
432 |
+
/**
|
433 |
+
* Keep the "primary" color of the dropdown arrow button, "Install Now" button, and
|
434 |
+
* "Download Latest" button.
|
435 |
+
|
436 |
+
* @author Leo Fajardo (@leorw)
|
437 |
+
* @since 2.2.4
|
438 |
+
*/
|
439 |
+
return $( this ).parent().is( ':not(.button-group)' );
|
440 |
+
}).removeClass('button-primary');
|
441 |
+
|
442 |
+
toggleDropdown( $this.find( '.fs-dropdown' ), false );
|
443 |
+
}).find( 'a.thickbox, .button:not(.fs-dropdown-arrow-button)' ).click(function() {
|
444 |
+
toggleDropdown();
|
445 |
+
});
|
446 |
+
|
447 |
+
<?php endif ?>
|
448 |
+
|
449 |
+
var $dropdowns = $( '.fs-dropdown' );
|
450 |
+
if ( 0 !== $dropdowns.length ) {
|
451 |
+
$dropdowns.find( '.fs-dropdown-arrow-button' ).click(function() {
|
452 |
+
var $this = $( this ),
|
453 |
+
$dropdown = $this.parents( '.fs-dropdown' );
|
454 |
+
|
455 |
+
toggleDropdown( $dropdown, ! $dropdown.hasClass( 'active' ) );
|
456 |
+
});
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* Returns the default state of the dropdown arrow button and hides the dropdown list.
|
461 |
+
*
|
462 |
+
* @author Leo Fajardo (@leorw)
|
463 |
+
* @since 2.2.4
|
464 |
+
*
|
465 |
+
* @param {(Object|undefined)} [$dropdown]
|
466 |
+
* @param {(Boolean|undefined)} [state]
|
467 |
+
*/
|
468 |
+
function toggleDropdown( $dropdown, state ) {
|
469 |
+
if ( undef === $dropdown ) {
|
470 |
+
var $activeDropdown = $dropdowns.find( '.active' );
|
471 |
+
if ( 0 !== $activeDropdown.length ) {
|
472 |
+
$dropdown = $activeDropdown;
|
473 |
+
}
|
474 |
+
}
|
475 |
+
|
476 |
+
if ( undef === $dropdown ) {
|
477 |
+
return;
|
478 |
+
}
|
479 |
+
|
480 |
+
if ( undef === state ) {
|
481 |
+
state = false;
|
482 |
+
}
|
483 |
+
|
484 |
+
$dropdown.toggleClass( 'active', state );
|
485 |
+
$dropdown.find( '.fs-dropdown-list' ).toggle( state );
|
486 |
+
$dropdown.find( '.fs-dropdown-arrow-button' ).toggleClass( 'active', state );
|
487 |
+
}
|
488 |
+
})( jQuery );
|
489 |
+
</script>
|
490 |
+
<?php
|
491 |
+
if ( $has_tabs ) {
|
492 |
+
$fs->_add_tabs_after_content();
|
493 |
+
}
|
494 |
+
|
495 |
+
$params = array(
|
496 |
+
'page' => 'addons',
|
497 |
+
'module_id' => $fs->get_id(),
|
498 |
+
'module_type' => $fs->get_module_type(),
|
499 |
+
'module_slug' => $slug,
|
500 |
+
'module_version' => $fs->get_plugin_version(),
|
501 |
+
);
|
502 |
fs_require_template( 'powered-by.php', $params );
|
freemius/templates/connect.php
CHANGED
@@ -1,1038 +1,1038 @@
|
|
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 1.0.7
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var array $VARS
|
15 |
-
* @var Freemius $fs
|
16 |
-
*/
|
17 |
-
$fs = freemius( $VARS['id'] );
|
18 |
-
$slug = $fs->get_slug();
|
19 |
-
|
20 |
-
$is_pending_activation = $fs->is_pending_activation();
|
21 |
-
$is_premium_only = $fs->is_only_premium();
|
22 |
-
$has_paid_plans = $fs->has_paid_plan();
|
23 |
-
$is_premium_code = $fs->is_premium();
|
24 |
-
$is_freemium = $fs->is_freemium();
|
25 |
-
|
26 |
-
$fs->_enqueue_connect_essentials();
|
27 |
-
|
28 |
-
$current_user = Freemius::_get_current_wp_user();
|
29 |
-
|
30 |
-
$first_name = $current_user->user_firstname;
|
31 |
-
if ( empty( $first_name ) ) {
|
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 );
|
39 |
-
}
|
40 |
-
|
41 |
-
$freemius_site_www = 'https://freemius.com';
|
42 |
-
|
43 |
-
$freemius_usage_tracking_url = $fs->get_usage_tracking_terms_url();
|
44 |
-
$freemius_plugin_terms_url = $fs->get_eula_url();
|
45 |
-
|
46 |
-
$freemius_site_url = $fs->is_premium() ?
|
47 |
-
$freemius_site_www :
|
48 |
-
$freemius_usage_tracking_url;
|
49 |
-
|
50 |
-
if ( $fs->is_premium() ) {
|
51 |
-
$freemius_site_url .= '?' . http_build_query( array(
|
52 |
-
'id' => $fs->get_id(),
|
53 |
-
'slug' => $slug,
|
54 |
-
) );
|
55 |
-
}
|
56 |
-
|
57 |
-
$freemius_link = '<a href="' . $freemius_site_url . '" target="_blank" rel="noopener" tabindex="1">freemius.com</a>';
|
58 |
-
|
59 |
-
$error = fs_request_get( 'error' );
|
60 |
-
|
61 |
-
$require_license_key = $is_premium_only ||
|
62 |
-
( $is_freemium && $is_premium_code && fs_request_get_bool( 'require_license', true ) );
|
63 |
-
|
64 |
-
if ( $is_pending_activation ) {
|
65 |
-
$require_license_key = false;
|
66 |
-
}
|
67 |
-
|
68 |
-
if ( $require_license_key ) {
|
69 |
-
$fs->_add_license_activation_dialog_box();
|
70 |
-
}
|
71 |
-
|
72 |
-
$is_optin_dialog = (
|
73 |
-
$fs->is_theme() &&
|
74 |
-
$fs->is_themes_page() &&
|
75 |
-
$fs->show_opt_in_on_themes_page()
|
76 |
-
);
|
77 |
-
|
78 |
-
if ( $is_optin_dialog ) {
|
79 |
-
$show_close_button = false;
|
80 |
-
$previous_theme_activation_url = '';
|
81 |
-
|
82 |
-
if ( ! $is_premium_code ) {
|
83 |
-
$show_close_button = true;
|
84 |
-
} else if ( $is_premium_only ) {
|
85 |
-
$previous_theme_activation_url = $fs->get_previous_theme_activation_url();
|
86 |
-
$show_close_button = ( ! empty( $previous_theme_activation_url ) );
|
87 |
-
}
|
88 |
-
}
|
89 |
-
|
90 |
-
$is_network_level_activation = (
|
91 |
-
fs_is_network_admin() &&
|
92 |
-
$fs->is_network_active() &&
|
93 |
-
! $fs->is_network_delegated_connection()
|
94 |
-
);
|
95 |
-
|
96 |
-
$fs_user = Freemius::_get_user_by_email( $current_user->user_email );
|
97 |
-
|
98 |
-
$activate_with_current_user = (
|
99 |
-
is_object( $fs_user ) &&
|
100 |
-
! $is_pending_activation &&
|
101 |
-
// If requires a license for activation, use the user associated with the license for the opt-in.
|
102 |
-
! $require_license_key &&
|
103 |
-
! $is_network_level_activation
|
104 |
-
);
|
105 |
-
|
106 |
-
$optin_params = $fs->get_opt_in_params( array(), $is_network_level_activation );
|
107 |
-
$sites = isset( $optin_params['sites'] ) ? $optin_params['sites'] : array();
|
108 |
-
|
109 |
-
$is_network_upgrade_mode = ( fs_is_network_admin() && $fs->is_network_upgrade_mode() );
|
110 |
-
|
111 |
-
/* translators: %s: name (e.g. Hey John,) */
|
112 |
-
$hey_x_text = esc_html( sprintf( fs_text_x_inline( 'Hey %s,', 'greeting', 'hey-x', $slug ), $first_name ) );
|
113 |
-
|
114 |
-
$is_gdpr_required = ( ! $is_pending_activation && ! $require_license_key ) ?
|
115 |
-
FS_GDPR_Manager::instance()->is_required() :
|
116 |
-
false;
|
117 |
-
|
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 ) { ?>
|
124 |
-
<div id="fs_theme_connect_wrapper">
|
125 |
-
<?php
|
126 |
-
if ( $show_close_button ) { ?>
|
127 |
-
<button class="close dashicons dashicons-no"><span class="screen-reader-text">Close connect dialog</span>
|
128 |
-
</button>
|
129 |
-
<?php
|
130 |
-
}
|
131 |
-
?>
|
132 |
-
<?php
|
133 |
-
}
|
134 |
-
|
135 |
-
/**
|
136 |
-
* Allows developers to include custom HTML before the opt-in content.
|
137 |
-
*
|
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 = '';
|
164 |
-
|
165 |
-
if ( $is_pending_activation ) {
|
166 |
-
$button_label = fs_text_inline( 'Re-send activation email', 'resend-activation-email', $slug );
|
167 |
-
|
168 |
-
$message = $fs->apply_filters( 'pending_activation_message', sprintf(
|
169 |
-
/* translators: %s: name (e.g. Thanks John!) */
|
170 |
-
fs_text_inline( 'Thanks %s!', 'thanks-x', $slug ) . '<br>' .
|
171 |
-
fs_text_inline( '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.', 'pending-activation-message', $slug ),
|
172 |
-
$first_name,
|
173 |
-
'<b>' . $fs->get_plugin_name() . '</b>',
|
174 |
-
'<b>' . $current_user->user_email . '</b>',
|
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',
|
184 |
-
sprintf( fs_text_inline( 'Welcome to %s! To get started, please enter your license key:', 'thanks-for-purchasing', $slug ), '<b>' . $fs->get_plugin_name() . '</b>' ),
|
185 |
-
$first_name,
|
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 |
-
}
|
207 |
-
}
|
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(),
|
225 |
-
$current_user->user_login,
|
226 |
-
'<a href="' . $site_url . '" target="_blank" rel="noopener noreferrer">' . $site_url . '</a>',
|
227 |
-
$freemius_link,
|
228 |
-
$is_gdpr_required
|
229 |
-
);
|
230 |
-
}
|
231 |
-
|
232 |
-
if ( $is_network_upgrade_mode ) {
|
233 |
-
$network_integration_text = esc_html( fs_text_inline( 'We\'re excited to introduce the Freemius network-level integration.', 'connect_message_network_upgrade', $slug ) );
|
234 |
-
|
235 |
-
if ($is_premium_code){
|
236 |
-
$message = $network_integration_text . ' ' . sprintf( fs_text_inline( 'During the update process we detected %d site(s) that are still pending license activation.', 'connect_message_network_upgrade-premium', $slug ), count( $sites ) );
|
237 |
-
|
238 |
-
$message .= '<br><br>' . sprintf( fs_text_inline( 'If you\'d like to use the %s on those sites, please enter your license key below and click the activation button.', 'connect_message_network_upgrade-premium-activate-license', $slug ), $is_premium_only ? $fs->get_module_label( true ) : sprintf(
|
239 |
-
/* translators: %s: module type (plugin, theme, or add-on) */
|
240 |
-
fs_text_inline( "%s's paid features", 'x-paid-features', $slug ),
|
241 |
-
$fs->get_module_label( true )
|
242 |
-
) );
|
243 |
-
|
244 |
-
/* translators: %s: module type (plugin, theme, or add-on) */
|
245 |
-
$message .= ' ' . sprintf( fs_text_inline( 'Alternatively, you can skip it for now and activate the license later, in your %s\'s network-level Account page.', 'connect_message_network_upgrade-premium-skip-license', $slug ), $fs->get_module_label( true ) );
|
246 |
-
}else {
|
247 |
-
$message = $network_integration_text . ' ' . sprintf( fs_text_inline( 'During the update process we detected %s site(s) in the network that are still pending your attention.', 'connect_message_network_upgrade-free', $slug ), count( $sites ) ) . '<br><br>' . ( fs_starts_with( $message, $hey_x_text . '<br>' ) ? substr( $message, strlen( $hey_x_text . '<br>' ) ) : $message );
|
248 |
-
}
|
249 |
-
}
|
250 |
-
|
251 |
-
echo $message;
|
252 |
-
?></p>
|
253 |
-
<?php if ( $require_license_key ) : ?>
|
254 |
-
<div class="fs-license-key-container">
|
255 |
-
<input id="fs_license_key" name="fs_key" type="text" required maxlength="<?php echo $fs->apply_filters('license_key_maxlength', 32) ?>"
|
256 |
-
placeholder="<?php fs_esc_attr_echo_inline( 'License key', 'license-key', $slug ) ?>" tabindex="1"/>
|
257 |
-
<i class="dashicons dashicons-admin-network"></i>
|
258 |
-
<a class="show-license-resend-modal show-license-resend-modal-<?php echo $fs->get_unique_affix() ?>"
|
259 |
-
href="#"><?php fs_esc_html_echo_inline( "Can't find your license key?", 'cant-find-license-key', $slug ); ?></a>
|
260 |
-
</div>
|
261 |
-
|
262 |
-
<?php
|
263 |
-
/**
|
264 |
-
* Allows developers to include custom HTML after the license input container.
|
265 |
-
*
|
266 |
-
* @author Vova Feldman
|
267 |
-
* @since 2.1.2
|
268 |
-
*/
|
269 |
-
$fs->do_action( 'connect/after_license_input' );
|
270 |
-
?>
|
271 |
-
|
272 |
-
<?php
|
273 |
-
$send_updates_text = sprintf(
|
274 |
-
'%s<span class="action-description"> - %s</span>',
|
275 |
-
$fs->get_text_inline( 'Yes', 'yes' ),
|
276 |
-
$fs->get_text_inline( 'send me security & feature updates, educational content and offers.', 'send-updates' )
|
277 |
-
);
|
278 |
-
|
279 |
-
$do_not_send_updates_text = sprintf(
|
280 |
-
'%s<span class="action-description"> - %s</span>',
|
281 |
-
$fs->get_text_inline( 'No', 'no' ),
|
282 |
-
sprintf(
|
283 |
-
$fs->get_text_inline( 'do %sNOT%s send me security & feature updates, educational content and offers.', 'do-not-send-updates' ),
|
284 |
-
'<span class="underlined">',
|
285 |
-
'</span>'
|
286 |
-
)
|
287 |
-
);
|
288 |
-
?>
|
289 |
-
<div id="fs_marketing_optin">
|
290 |
-
<span class="fs-message"><?php fs_echo_inline( "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:", 'contact-for-updates' ) ?></span>
|
291 |
-
<div class="fs-input-container">
|
292 |
-
<label>
|
293 |
-
<input type="radio" name="allow-marketing" value="true" tabindex="1" />
|
294 |
-
<span class="fs-input-label"><?php echo $send_updates_text ?></span>
|
295 |
-
</label>
|
296 |
-
<label>
|
297 |
-
<input type="radio" name="allow-marketing" value="false" tabindex="1" />
|
298 |
-
<span class="fs-input-label"><?php echo $do_not_send_updates_text ?></span>
|
299 |
-
</label>
|
300 |
-
</div>
|
301 |
-
</div>
|
302 |
-
<?php endif ?>
|
303 |
-
<?php if ( $is_network_level_activation ) : ?>
|
304 |
-
<?php
|
305 |
-
$vars = array(
|
306 |
-
'id' => $fs->get_id(),
|
307 |
-
'sites' => $sites,
|
308 |
-
'require_license_key' => $require_license_key
|
309 |
-
);
|
310 |
-
|
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>
|
319 |
-
<?php endif ?>
|
320 |
-
<?php if ( $is_network_level_activation && $fs->apply_filters( 'show_delegation_option', true ) ) : ?>
|
321 |
-
<a id="delegate_to_site_admins" class="fs-tooltip-trigger <?php echo is_rtl() ? ' rtl' : '' ?>" href="<?php echo fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_delegate_activation' ) ), $fs->get_unique_affix() . '_delegate_activation' ) ?>"><?php fs_esc_html_echo_inline( 'Delegate to Site Admins', 'delegate-to-site-admins', $slug ) ?><span class="fs-tooltip"><?php fs_esc_html_echo_inline( 'If you click it, this decision will be delegated to the sites administrators.', 'delegate-sites-tooltip', $slug ) ?></span></a>
|
322 |
-
<?php endif ?>
|
323 |
-
<?php if ( $activate_with_current_user ) : ?>
|
324 |
-
<form action="" method="POST">
|
325 |
-
<input type="hidden" name="fs_action"
|
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>
|
332 |
-
<?php else : ?>
|
333 |
-
<form method="post" action="<?php echo WP_FS__ADDRESS ?>/action/service/user/install/">
|
334 |
-
<?php unset( $optin_params['sites']); ?>
|
335 |
-
<?php foreach ( $optin_params as $name => $value ) : ?>
|
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"';
|
342 |
-
} ?>><?php echo esc_html( $button_label ) ?></button>
|
343 |
-
</form>
|
344 |
-
<?php endif ?>
|
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 ) : ?>
|
454 |
-
<div class="fs-freemium-licensing">
|
455 |
-
<p>
|
456 |
-
<?php if ( $require_license_key ) : ?>
|
457 |
-
<?php fs_esc_html_echo_inline( 'Don\'t have a license key?', 'dont-have-license-key', $slug ) ?>
|
458 |
-
<a data-require-license="false" tabindex="1"><?php fs_esc_html_echo_inline( 'Activate Free Version', 'activate-free-version', $slug ) ?></a>
|
459 |
-
<?php else : ?>
|
460 |
-
<?php fs_echo_inline( 'Have a license key?', 'have-license-key', $slug ) ?>
|
461 |
-
<a data-require-license="true" tabindex="1"><?php fs_esc_html_echo_inline( 'Activate License', 'activate-license', $slug ) ?></a>
|
462 |
-
<?php endif ?>
|
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 |
-
-
|
470 |
-
<a href="<?php echo $require_license_key ? $freemius_plugin_terms_url : $freemius_usage_tracking_url ?>" target="_blank" rel="noopener" tabindex="1"><?php $require_license_key ? fs_echo_inline( 'License Agreement', 'license-agreement', $slug ) : fs_echo_inline( 'Terms of Service', 'tos', $slug ) ?></a>
|
471 |
-
</div>
|
472 |
-
</div>
|
473 |
-
<?php
|
474 |
-
/**
|
475 |
-
* Allows developers to include custom HTML after the opt-in content.
|
476 |
-
*
|
477 |
-
* @author Vova Feldman
|
478 |
-
* @since 2.3.2
|
479 |
-
*/
|
480 |
-
$fs->do_action( 'connect/after' );
|
481 |
-
|
482 |
-
if ( $is_optin_dialog ) { ?>
|
483 |
-
</div>
|
484 |
-
<?php
|
485 |
-
}
|
486 |
-
?>
|
487 |
-
<script type="text/javascript">
|
488 |
-
(function ($) {
|
489 |
-
var $html = $('html');
|
490 |
-
|
491 |
-
<?php
|
492 |
-
if ( $is_optin_dialog ) {
|
493 |
-
if ( $show_close_button ) { ?>
|
494 |
-
var $themeConnectWrapper = $('#fs_theme_connect_wrapper');
|
495 |
-
|
496 |
-
$themeConnectWrapper.find('button.close').on('click', function () {
|
497 |
-
<?php if ( ! empty( $previous_theme_activation_url ) ) { ?>
|
498 |
-
location.href = '<?php echo html_entity_decode( $previous_theme_activation_url ); ?>';
|
499 |
-
<?php } else { ?>
|
500 |
-
$themeConnectWrapper.remove();
|
501 |
-
$html.css({overflow: $html.attr('fs-optin-overflow')});
|
502 |
-
<?php } ?>
|
503 |
-
});
|
504 |
-
<?php
|
505 |
-
}
|
506 |
-
?>
|
507 |
-
|
508 |
-
$html.attr('fs-optin-overflow', $html.css('overflow'));
|
509 |
-
$html.css({overflow: 'hidden'});
|
510 |
-
|
511 |
-
<?php
|
512 |
-
}
|
513 |
-
?>
|
514 |
-
|
515 |
-
var $primaryCta = $('.fs-actions .button.button-primary'),
|
516 |
-
primaryCtaLabel = $primaryCta.html(),
|
517 |
-
$form = $('.fs-actions form'),
|
518 |
-
isNetworkActive = <?php echo $is_network_level_activation ? 'true' : 'false' ?>,
|
519 |
-
requireLicenseKey = <?php echo $require_license_key ? 'true' : 'false' ?>,
|
520 |
-
hasContextUser = <?php echo $activate_with_current_user ? 'true' : 'false' ?>,
|
521 |
-
isNetworkUpgradeMode = <?php echo $is_network_upgrade_mode ? 'true' : 'false' ?>,
|
522 |
-
$licenseSecret,
|
523 |
-
$licenseKeyInput = $('#fs_license_key'),
|
524 |
-
pauseCtaLabelUpdate = false,
|
525 |
-
isNetworkDelegating = false,
|
526 |
-
/**
|
527 |
-
* @author Leo Fajardo (@leorw)
|
528 |
-
* @since 2.1.0
|
529 |
-
*/
|
530 |
-
resetLoadingMode = function() {
|
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 () {
|
544 |
-
setLoadingMode();
|
545 |
-
|
546 |
-
var $this = $(this);
|
547 |
-
|
548 |
-
setTimeout(function () {
|
549 |
-
if ( ! requireLicenseKey || ! $marketingOptin.hasClass( 'error' ) ) {
|
550 |
-
$this.attr('disabled', 'disabled');
|
551 |
-
}
|
552 |
-
}, 200);
|
553 |
-
});
|
554 |
-
|
555 |
-
if ( isNetworkActive ) {
|
556 |
-
var
|
557 |
-
$multisiteOptionsContainer = $( '.fs-multisite-options-container' ),
|
558 |
-
$allSitesOptions = $( '.fs-all-sites-options' ),
|
559 |
-
$applyOnAllSites = $( '.fs-apply-on-all-sites-checkbox' ),
|
560 |
-
$sitesListContainer = $( '.fs-sites-list-container' ),
|
561 |
-
totalSites = <?php echo count( $sites ) ?>,
|
562 |
-
maxSitesListHeight = null,
|
563 |
-
$skipActivationButton = $( '#skip_activation' ),
|
564 |
-
$delegateToSiteAdminsButton = $( '#delegate_to_site_admins' ),
|
565 |
-
hasAnyInstall = <?php echo ! is_null( $fs->find_first_install() ) ? 'true' : 'false' ?>;
|
566 |
-
|
567 |
-
$applyOnAllSites.click(function() {
|
568 |
-
var isChecked = $( this ).is( ':checked' );
|
569 |
-
|
570 |
-
if ( isChecked ) {
|
571 |
-
$multisiteOptionsContainer.find( '.action' ).removeClass( 'selected' );
|
572 |
-
updatePrimaryCtaText( 'allow' );
|
573 |
-
}
|
574 |
-
|
575 |
-
$multisiteOptionsContainer.find( '.action-allow' ).addClass( 'selected' );
|
576 |
-
|
577 |
-
$skipActivationButton.toggle();
|
578 |
-
|
579 |
-
$delegateToSiteAdminsButton.toggle();
|
580 |
-
|
581 |
-
$multisiteOptionsContainer.toggleClass( 'fs-apply-on-all-sites', isChecked );
|
582 |
-
|
583 |
-
$sitesListContainer.toggle( ! isChecked );
|
584 |
-
if ( ! isChecked && null === maxSitesListHeight ) {
|
585 |
-
/**
|
586 |
-
* Set the visible number of rows to 5 (5 * height of the first row).
|
587 |
-
*
|
588 |
-
* @author Leo Fajardo (@leorw)
|
589 |
-
*/
|
590 |
-
maxSitesListHeight = ( 5 * $sitesListContainer.find( 'tr:first' ).height() );
|
591 |
-
$sitesListContainer.css( 'max-height', maxSitesListHeight );
|
592 |
-
}
|
593 |
-
});
|
594 |
-
|
595 |
-
$allSitesOptions.find( '.action' ).click(function( evt ) {
|
596 |
-
var actionType = $( evt.target ).data( 'action-type' );
|
597 |
-
|
598 |
-
$multisiteOptionsContainer.find( '.action' ).removeClass( 'selected' );
|
599 |
-
$multisiteOptionsContainer.find( '.action-' + actionType ).toggleClass( 'selected' );
|
600 |
-
|
601 |
-
updatePrimaryCtaText( actionType );
|
602 |
-
});
|
603 |
-
|
604 |
-
$sitesListContainer.delegate( '.action', 'click', function( evt ) {
|
605 |
-
var $this = $( evt.target );
|
606 |
-
if ( $this.hasClass( 'selected' ) ) {
|
607 |
-
return false;
|
608 |
-
}
|
609 |
-
|
610 |
-
$this.parents( 'tr:first' ).find( '.action' ).removeClass( 'selected' );
|
611 |
-
$this.toggleClass( 'selected' );
|
612 |
-
|
613 |
-
var
|
614 |
-
singleSiteActionType = $this.data( 'action-type' ),
|
615 |
-
totalSelected = $sitesListContainer.find( '.action-' + singleSiteActionType + '.selected' ).length;
|
616 |
-
|
617 |
-
$allSitesOptions.find( '.action.selected' ).removeClass( 'selected' );
|
618 |
-
|
619 |
-
if ( totalSelected === totalSites ) {
|
620 |
-
$allSitesOptions.find( '.action-' + singleSiteActionType ).addClass( 'selected' );
|
621 |
-
|
622 |
-
updatePrimaryCtaText( singleSiteActionType );
|
623 |
-
} else {
|
624 |
-
updatePrimaryCtaText( 'mixed' );
|
625 |
-
}
|
626 |
-
});
|
627 |
-
|
628 |
-
if ( isNetworkUpgradeMode || hasAnyInstall ) {
|
629 |
-
$skipActivationButton.click(function(){
|
630 |
-
$delegateToSiteAdminsButton.hide();
|
631 |
-
|
632 |
-
$skipActivationButton.html('<?php fs_esc_js_echo_inline( 'Skipping, please wait', 'skipping-wait', $slug ) ?>...');
|
633 |
-
|
634 |
-
pauseCtaLabelUpdate = true;
|
635 |
-
|
636 |
-
// Check all sites to be skipped.
|
637 |
-
$allSitesOptions.find('.action.action-skip').click();
|
638 |
-
|
639 |
-
$form.submit();
|
640 |
-
|
641 |
-
pauseCtaLabelUpdate = false;
|
642 |
-
|
643 |
-
return false;
|
644 |
-
});
|
645 |
-
|
646 |
-
$delegateToSiteAdminsButton.click(function(){
|
647 |
-
$delegateToSiteAdminsButton.html('<?php fs_esc_js_echo_inline( 'Delegating, please wait', 'delegating-wait', $slug ) ?>...');
|
648 |
-
|
649 |
-
pauseCtaLabelUpdate = true;
|
650 |
-
|
651 |
-
/**
|
652 |
-
* Set to true so that the form submission handler can differentiate delegation from license
|
653 |
-
* activation and the proper AJAX action will be used (when delegating, the action should be
|
654 |
-
* `network_activate` and not `activate_license`).
|
655 |
-
*
|
656 |
-
* @author Leo Fajardo (@leorw)
|
657 |
-
* @since 2.3.0
|
658 |
-
*/
|
659 |
-
isNetworkDelegating = true;
|
660 |
-
|
661 |
-
// Check all sites to be skipped.
|
662 |
-
$allSitesOptions.find('.action.action-delegate').click();
|
663 |
-
|
664 |
-
$form.submit();
|
665 |
-
|
666 |
-
pauseCtaLabelUpdate = false;
|
667 |
-
|
668 |
-
/**
|
669 |
-
* Set to false so that in case the previous AJAX request has failed, the form submission handler
|
670 |
-
* can differentiate license activation from delegation and the proper AJAX action will be used
|
671 |
-
* (when activating a license, the action should be `activate_license` and not `network_activate`).
|
672 |
-
*
|
673 |
-
* @author Leo Fajardo (@leorw)
|
674 |
-
* @since 2.3.0
|
675 |
-
*/
|
676 |
-
isNetworkDelegating = false;
|
677 |
-
|
678 |
-
return false;
|
679 |
-
});
|
680 |
-
}
|
681 |
-
}
|
682 |
-
|
683 |
-
/**
|
684 |
-
* @author Leo Fajardo (@leorw)
|
685 |
-
*/
|
686 |
-
function updatePrimaryCtaText( actionType ) {
|
687 |
-
if (pauseCtaLabelUpdate)
|
688 |
-
return;
|
689 |
-
|
690 |
-
var text = '<?php fs_esc_js_echo_inline( 'Continue', 'continue', $slug ) ?>';
|
691 |
-
|
692 |
-
switch ( actionType ) {
|
693 |
-
case 'allow':
|
694 |
-
text = '<?php fs_esc_js_echo_inline( 'Allow & Continue', 'opt-in-connect', $slug ) ?>';
|
695 |
-
break;
|
696 |
-
case 'delegate':
|
697 |
-
text = '<?php fs_esc_js_echo_inline( 'Delegate to Site Admins & Continue', 'delegate-to-site-admins-and-continue', $slug ) ?>';
|
698 |
-
break;
|
699 |
-
case 'skip':
|
700 |
-
text = '<?php fs_esc_js_echo_x_inline( 'Skip', 'verb', 'skip', $slug ) ?>';
|
701 |
-
break;
|
702 |
-
}
|
703 |
-
|
704 |
-
$primaryCta.html( text );
|
705 |
-
}
|
706 |
-
|
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 |
-
/**
|
722 |
-
* @author Vova Feldman (@svovaf)
|
723 |
-
* @since 1.1.9
|
724 |
-
*/
|
725 |
-
if ( ajaxOptin ) {
|
726 |
-
if (!hasContextUser || isNetworkUpgradeMode) {
|
727 |
-
var action = null,
|
728 |
-
security = null;
|
729 |
-
|
730 |
-
if ( requireLicenseKey && ! isNetworkDelegating ) {
|
731 |
-
action = '<?php echo $fs->get_ajax_action( 'activate_license' ) ?>';
|
732 |
-
security = '<?php echo $fs->get_ajax_security( 'activate_license' ) ?>';
|
733 |
-
} else {
|
734 |
-
action = '<?php echo $fs->get_ajax_action( 'network_activate' ) ?>';
|
735 |
-
security = '<?php echo $fs->get_ajax_security( 'network_activate' ) ?>';
|
736 |
-
}
|
737 |
-
|
738 |
-
$('.fs-error').remove();
|
739 |
-
|
740 |
-
var
|
741 |
-
licenseKey = $licenseKeyInput.val(),
|
742 |
-
data = {
|
743 |
-
action : action,
|
744 |
-
security : security,
|
745 |
-
license_key: licenseKey,
|
746 |
-
module_id : '<?php echo $fs->get_id() ?>'
|
747 |
-
};
|
748 |
-
|
749 |
-
if (
|
750 |
-
requireLicenseKey &&
|
751 |
-
! isNetworkDelegating &&
|
752 |
-
isMarketingAllowedByLicense.hasOwnProperty(licenseKey)
|
753 |
-
) {
|
754 |
-
var
|
755 |
-
isMarketingAllowed = null,
|
756 |
-
$isMarketingAllowed = $marketingOptin.find( 'input[type="radio"][name="allow-marketing"]:checked');
|
757 |
-
|
758 |
-
|
759 |
-
if ($isMarketingAllowed.length > 0)
|
760 |
-
isMarketingAllowed = ('true' == $isMarketingAllowed.val());
|
761 |
-
|
762 |
-
if ( null == isMarketingAllowedByLicense[ licenseKey ] &&
|
763 |
-
null == isMarketingAllowed
|
764 |
-
) {
|
765 |
-
$marketingOptin.addClass( 'error' ).show();
|
766 |
-
resetLoadingMode();
|
767 |
-
return false;
|
768 |
-
} else if ( null == isMarketingAllowed ) {
|
769 |
-
isMarketingAllowed = isMarketingAllowedByLicense[ licenseKey ];
|
770 |
-
}
|
771 |
-
|
772 |
-
data.is_marketing_allowed = isMarketingAllowed;
|
773 |
-
|
774 |
-
data.is_extensions_tracking_allowed = isExtensionsTrackingAllowed;
|
775 |
-
}
|
776 |
-
|
777 |
-
$marketingOptin.removeClass( 'error' );
|
778 |
-
|
779 |
-
if ( isNetworkActive ) {
|
780 |
-
var
|
781 |
-
sites = [],
|
782 |
-
applyOnAllSites = $applyOnAllSites.is( ':checked' );
|
783 |
-
|
784 |
-
$sitesListContainer.find( 'tr' ).each(function() {
|
785 |
-
var
|
786 |
-
$this = $( this ),
|
787 |
-
includeSite = ( ! requireLicenseKey || applyOnAllSites || $this.find( 'input' ).is( ':checked' ) );
|
788 |
-
|
789 |
-
if ( ! includeSite )
|
790 |
-
return;
|
791 |
-
|
792 |
-
var site = {
|
793 |
-
uid : $this.find( '.uid' ).val(),
|
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 |
-
|
801 |
-
if ( ! requireLicenseKey) {
|
802 |
-
site.action = $this.find('.action.selected').data('action-type');
|
803 |
-
} else if ( isNetworkDelegating ) {
|
804 |
-
site.action = 'delegate';
|
805 |
-
}
|
806 |
-
|
807 |
-
sites.push( site );
|
808 |
-
});
|
809 |
-
|
810 |
-
data.sites = sites;
|
811 |
-
|
812 |
-
if ( hasAnyInstall ) {
|
813 |
-
data.has_any_install = hasAnyInstall;
|
814 |
-
}
|
815 |
-
}
|
816 |
-
|
817 |
-
/**
|
818 |
-
* Use the AJAX opt-in when license key is required to potentially
|
819 |
-
* process the after install failure hook.
|
820 |
-
*
|
821 |
-
* @author Vova Feldman (@svovaf)
|
822 |
-
* @since 1.2.1.5
|
823 |
-
*/
|
824 |
-
$.ajax({
|
825 |
-
url : ajaxurl,
|
826 |
-
method : 'POST',
|
827 |
-
data : data,
|
828 |
-
success: function (result) {
|
829 |
-
var resultObj = $.parseJSON(result);
|
830 |
-
if (resultObj.success) {
|
831 |
-
// Redirect to the "Account" page and sync the license.
|
832 |
-
window.location.href = resultObj.next_page;
|
833 |
-
} else {
|
834 |
-
resetLoadingMode();
|
835 |
-
|
836 |
-
// Show error.
|
837 |
-
$('.fs-content').prepend('<p class="fs-error">' + (resultObj.error.message ? resultObj.error.message : resultObj.error) + '</p>');
|
838 |
-
}
|
839 |
-
},
|
840 |
-
error: function () {
|
841 |
-
resetLoadingMode();
|
842 |
-
}
|
843 |
-
});
|
844 |
-
|
845 |
-
return false;
|
846 |
-
}
|
847 |
-
else {
|
848 |
-
if (null == $licenseSecret) {
|
849 |
-
$licenseSecret = $('<input type="hidden" name="license_secret_key" value="" />');
|
850 |
-
$form.append($licenseSecret);
|
851 |
-
}
|
852 |
-
|
853 |
-
// Update secret key if premium only plugin.
|
854 |
-
$licenseSecret.val($licenseKeyInput.val());
|
855 |
-
}
|
856 |
-
}
|
857 |
-
|
858 |
-
return true;
|
859 |
-
});
|
860 |
-
|
861 |
-
$primaryCta.on('click', function () {
|
862 |
-
console.log('Primary button was clicked');
|
863 |
-
|
864 |
-
$(this).addClass('fs-loading');
|
865 |
-
$(this).html('<?php echo esc_js( $is_pending_activation ?
|
866 |
-
fs_text_x_inline( 'Sending email', 'as in the process of sending an email', 'sending-email', $slug ) :
|
867 |
-
fs_text_x_inline( 'Activating', 'as activating plugin', 'activating', $slug )
|
868 |
-
) ?>...');
|
869 |
-
});
|
870 |
-
|
871 |
-
$('.fs-permissions .fs-trigger').on('click', function () {
|
872 |
-
$('.fs-permissions').toggleClass('fs-open');
|
873 |
-
|
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.
|
886 |
-
*
|
887 |
-
* @author Vova Feldman (@svovaf)
|
888 |
-
* @since 1.1.9
|
889 |
-
*/
|
890 |
-
$licenseKeyInput.keypress(function (e) {
|
891 |
-
if (e.which == 13) {
|
892 |
-
if ('' !== $(this).val()) {
|
893 |
-
$primaryCta.click();
|
894 |
-
return false;
|
895 |
-
}
|
896 |
-
}
|
897 |
-
});
|
898 |
-
|
899 |
-
/**
|
900 |
-
* Disable activation button when empty license key.
|
901 |
-
*
|
902 |
-
* @author Vova Feldman (@svovaf)
|
903 |
-
* @since 1.1.9
|
904 |
-
*/
|
905 |
-
$licenseKeyInput.on('keyup paste delete cut', function () {
|
906 |
-
setTimeout(function () {
|
907 |
-
var key = $licenseKeyInput.val();
|
908 |
-
|
909 |
-
if (key == previousLicenseKey){
|
910 |
-
return;
|
911 |
-
}
|
912 |
-
|
913 |
-
if ('' === key) {
|
914 |
-
$primaryCta.attr('disabled', 'disabled');
|
915 |
-
$marketingOptin.hide();
|
916 |
-
} else {
|
917 |
-
$primaryCta.prop('disabled', false);
|
918 |
-
|
919 |
-
if (32 <= key.length){
|
920 |
-
fetchIsMarketingAllowedFlagAndToggleOptin();
|
921 |
-
} else {
|
922 |
-
$marketingOptin.hide();
|
923 |
-
}
|
924 |
-
}
|
925 |
-
|
926 |
-
previousLicenseKey = key;
|
927 |
-
}, 100);
|
928 |
-
}).focus();
|
929 |
-
}
|
930 |
-
|
931 |
-
/**
|
932 |
-
* Set license mode trigger URL.
|
933 |
-
*
|
934 |
-
* @author Vova Feldman (@svovaf)
|
935 |
-
* @since 1.1.9
|
936 |
-
*/
|
937 |
-
var
|
938 |
-
$connectLicenseModeTrigger = $('#fs_connect .fs-freemium-licensing a'),
|
939 |
-
href = window.location.href;
|
940 |
-
|
941 |
-
if (href.indexOf('?') > 0) {
|
942 |
-
href += '&';
|
943 |
-
} else {
|
944 |
-
href += '?';
|
945 |
-
}
|
946 |
-
|
947 |
-
if ($connectLicenseModeTrigger.length > 0) {
|
948 |
-
$connectLicenseModeTrigger.attr(
|
949 |
-
'href',
|
950 |
-
href + 'require_license=' + $connectLicenseModeTrigger.attr('data-require-license')
|
951 |
-
);
|
952 |
-
}
|
953 |
-
|
954 |
-
//--------------------------------------------------------------------------------
|
955 |
-
//region GDPR
|
956 |
-
//--------------------------------------------------------------------------------
|
957 |
-
var isMarketingAllowedByLicense = {},
|
958 |
-
$marketingOptin = $('#fs_marketing_optin'),
|
959 |
-
previousLicenseKey = null;
|
960 |
-
|
961 |
-
if (requireLicenseKey) {
|
962 |
-
|
963 |
-
var
|
964 |
-
afterMarketingFlagLoaded = function () {
|
965 |
-
var licenseKey = $licenseKeyInput.val();
|
966 |
-
|
967 |
-
if (null == isMarketingAllowedByLicense[licenseKey]) {
|
968 |
-
$marketingOptin.show();
|
969 |
-
|
970 |
-
if ($marketingOptin.find('input[type=radio]:checked').length > 0){
|
971 |
-
// Focus on button if GDPR opt-in already selected is already selected.
|
972 |
-
$primaryCta.focus();
|
973 |
-
} else {
|
974 |
-
// Focus on the GDPR opt-in radio button.
|
975 |
-
$($marketingOptin.find('input[type=radio]')[0]).focus();
|
976 |
-
}
|
977 |
-
} else {
|
978 |
-
$marketingOptin.hide();
|
979 |
-
$primaryCta.focus();
|
980 |
-
}
|
981 |
-
},
|
982 |
-
/**
|
983 |
-
* @author Leo Fajardo (@leorw)
|
984 |
-
* @since 2.1.0
|
985 |
-
*/
|
986 |
-
fetchIsMarketingAllowedFlagAndToggleOptin = function () {
|
987 |
-
var licenseKey = $licenseKeyInput.val();
|
988 |
-
|
989 |
-
if (licenseKey.length < 32) {
|
990 |
-
$marketingOptin.hide();
|
991 |
-
return;
|
992 |
-
}
|
993 |
-
|
994 |
-
if (isMarketingAllowedByLicense.hasOwnProperty(licenseKey)) {
|
995 |
-
afterMarketingFlagLoaded();
|
996 |
-
return;
|
997 |
-
}
|
998 |
-
|
999 |
-
$marketingOptin.hide();
|
1000 |
-
|
1001 |
-
setLoadingMode();
|
1002 |
-
|
1003 |
-
$primaryCta.addClass('fs-loading');
|
1004 |
-
$primaryCta.attr('disabled', 'disabled');
|
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' ) ?>',
|
1012 |
-
security : '<?php echo $fs->get_ajax_security( 'fetch_is_marketing_required_flag_value' ) ?>',
|
1013 |
-
license_key: licenseKey,
|
1014 |
-
module_id : '<?php echo $fs->get_id() ?>'
|
1015 |
-
},
|
1016 |
-
success: function (result) {
|
1017 |
-
resetLoadingMode();
|
1018 |
-
|
1019 |
-
if (result.success) {
|
1020 |
-
result = result.data;
|
1021 |
-
|
1022 |
-
// Cache result.
|
1023 |
-
isMarketingAllowedByLicense[licenseKey] = result.is_marketing_allowed;
|
1024 |
-
}
|
1025 |
-
|
1026 |
-
afterMarketingFlagLoaded();
|
1027 |
-
}
|
1028 |
-
});
|
1029 |
-
};
|
1030 |
-
|
1031 |
-
$marketingOptin.find( 'input' ).click(function() {
|
1032 |
-
$marketingOptin.removeClass( 'error' );
|
1033 |
-
});
|
1034 |
-
}
|
1035 |
-
|
1036 |
-
//endregion
|
1037 |
-
})(jQuery);
|
1038 |
</script>
|
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 1.0.7
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var array $VARS
|
15 |
+
* @var Freemius $fs
|
16 |
+
*/
|
17 |
+
$fs = freemius( $VARS['id'] );
|
18 |
+
$slug = $fs->get_slug();
|
19 |
+
|
20 |
+
$is_pending_activation = $fs->is_pending_activation();
|
21 |
+
$is_premium_only = $fs->is_only_premium();
|
22 |
+
$has_paid_plans = $fs->has_paid_plan();
|
23 |
+
$is_premium_code = $fs->is_premium();
|
24 |
+
$is_freemium = $fs->is_freemium();
|
25 |
+
|
26 |
+
$fs->_enqueue_connect_essentials();
|
27 |
+
|
28 |
+
$current_user = Freemius::_get_current_wp_user();
|
29 |
+
|
30 |
+
$first_name = $current_user->user_firstname;
|
31 |
+
if ( empty( $first_name ) ) {
|
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 );
|
39 |
+
}
|
40 |
+
|
41 |
+
$freemius_site_www = 'https://freemius.com';
|
42 |
+
|
43 |
+
$freemius_usage_tracking_url = $fs->get_usage_tracking_terms_url();
|
44 |
+
$freemius_plugin_terms_url = $fs->get_eula_url();
|
45 |
+
|
46 |
+
$freemius_site_url = $fs->is_premium() ?
|
47 |
+
$freemius_site_www :
|
48 |
+
$freemius_usage_tracking_url;
|
49 |
+
|
50 |
+
if ( $fs->is_premium() ) {
|
51 |
+
$freemius_site_url .= '?' . http_build_query( array(
|
52 |
+
'id' => $fs->get_id(),
|
53 |
+
'slug' => $slug,
|
54 |
+
) );
|
55 |
+
}
|
56 |
+
|
57 |
+
$freemius_link = '<a href="' . $freemius_site_url . '" target="_blank" rel="noopener" tabindex="1">freemius.com</a>';
|
58 |
+
|
59 |
+
$error = fs_request_get( 'error' );
|
60 |
+
|
61 |
+
$require_license_key = $is_premium_only ||
|
62 |
+
( $is_freemium && $is_premium_code && fs_request_get_bool( 'require_license', true ) );
|
63 |
+
|
64 |
+
if ( $is_pending_activation ) {
|
65 |
+
$require_license_key = false;
|
66 |
+
}
|
67 |
+
|
68 |
+
if ( $require_license_key ) {
|
69 |
+
$fs->_add_license_activation_dialog_box();
|
70 |
+
}
|
71 |
+
|
72 |
+
$is_optin_dialog = (
|
73 |
+
$fs->is_theme() &&
|
74 |
+
$fs->is_themes_page() &&
|
75 |
+
$fs->show_opt_in_on_themes_page()
|
76 |
+
);
|
77 |
+
|
78 |
+
if ( $is_optin_dialog ) {
|
79 |
+
$show_close_button = false;
|
80 |
+
$previous_theme_activation_url = '';
|
81 |
+
|
82 |
+
if ( ! $is_premium_code ) {
|
83 |
+
$show_close_button = true;
|
84 |
+
} else if ( $is_premium_only ) {
|
85 |
+
$previous_theme_activation_url = $fs->get_previous_theme_activation_url();
|
86 |
+
$show_close_button = ( ! empty( $previous_theme_activation_url ) );
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
$is_network_level_activation = (
|
91 |
+
fs_is_network_admin() &&
|
92 |
+
$fs->is_network_active() &&
|
93 |
+
! $fs->is_network_delegated_connection()
|
94 |
+
);
|
95 |
+
|
96 |
+
$fs_user = Freemius::_get_user_by_email( $current_user->user_email );
|
97 |
+
|
98 |
+
$activate_with_current_user = (
|
99 |
+
is_object( $fs_user ) &&
|
100 |
+
! $is_pending_activation &&
|
101 |
+
// If requires a license for activation, use the user associated with the license for the opt-in.
|
102 |
+
! $require_license_key &&
|
103 |
+
! $is_network_level_activation
|
104 |
+
);
|
105 |
+
|
106 |
+
$optin_params = $fs->get_opt_in_params( array(), $is_network_level_activation );
|
107 |
+
$sites = isset( $optin_params['sites'] ) ? $optin_params['sites'] : array();
|
108 |
+
|
109 |
+
$is_network_upgrade_mode = ( fs_is_network_admin() && $fs->is_network_upgrade_mode() );
|
110 |
+
|
111 |
+
/* translators: %s: name (e.g. Hey John,) */
|
112 |
+
$hey_x_text = esc_html( sprintf( fs_text_x_inline( 'Hey %s,', 'greeting', 'hey-x', $slug ), $first_name ) );
|
113 |
+
|
114 |
+
$is_gdpr_required = ( ! $is_pending_activation && ! $require_license_key ) ?
|
115 |
+
FS_GDPR_Manager::instance()->is_required() :
|
116 |
+
false;
|
117 |
+
|
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 ) { ?>
|
124 |
+
<div id="fs_theme_connect_wrapper">
|
125 |
+
<?php
|
126 |
+
if ( $show_close_button ) { ?>
|
127 |
+
<button class="close dashicons dashicons-no"><span class="screen-reader-text">Close connect dialog</span>
|
128 |
+
</button>
|
129 |
+
<?php
|
130 |
+
}
|
131 |
+
?>
|
132 |
+
<?php
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Allows developers to include custom HTML before the opt-in content.
|
137 |
+
*
|
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 = '';
|
164 |
+
|
165 |
+
if ( $is_pending_activation ) {
|
166 |
+
$button_label = fs_text_inline( 'Re-send activation email', 'resend-activation-email', $slug );
|
167 |
+
|
168 |
+
$message = $fs->apply_filters( 'pending_activation_message', sprintf(
|
169 |
+
/* translators: %s: name (e.g. Thanks John!) */
|
170 |
+
fs_text_inline( 'Thanks %s!', 'thanks-x', $slug ) . '<br>' .
|
171 |
+
fs_text_inline( '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.', 'pending-activation-message', $slug ),
|
172 |
+
$first_name,
|
173 |
+
'<b>' . $fs->get_plugin_name() . '</b>',
|
174 |
+
'<b>' . $current_user->user_email . '</b>',
|
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',
|
184 |
+
sprintf( fs_text_inline( 'Welcome to %s! To get started, please enter your license key:', 'thanks-for-purchasing', $slug ), '<b>' . $fs->get_plugin_name() . '</b>' ),
|
185 |
+
$first_name,
|
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 |
+
}
|
207 |
+
}
|
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(),
|
225 |
+
$current_user->user_login,
|
226 |
+
'<a href="' . $site_url . '" target="_blank" rel="noopener noreferrer">' . $site_url . '</a>',
|
227 |
+
$freemius_link,
|
228 |
+
$is_gdpr_required
|
229 |
+
);
|
230 |
+
}
|
231 |
+
|
232 |
+
if ( $is_network_upgrade_mode ) {
|
233 |
+
$network_integration_text = esc_html( fs_text_inline( 'We\'re excited to introduce the Freemius network-level integration.', 'connect_message_network_upgrade', $slug ) );
|
234 |
+
|
235 |
+
if ($is_premium_code){
|
236 |
+
$message = $network_integration_text . ' ' . sprintf( fs_text_inline( 'During the update process we detected %d site(s) that are still pending license activation.', 'connect_message_network_upgrade-premium', $slug ), count( $sites ) );
|
237 |
+
|
238 |
+
$message .= '<br><br>' . sprintf( fs_text_inline( 'If you\'d like to use the %s on those sites, please enter your license key below and click the activation button.', 'connect_message_network_upgrade-premium-activate-license', $slug ), $is_premium_only ? $fs->get_module_label( true ) : sprintf(
|
239 |
+
/* translators: %s: module type (plugin, theme, or add-on) */
|
240 |
+
fs_text_inline( "%s's paid features", 'x-paid-features', $slug ),
|
241 |
+
$fs->get_module_label( true )
|
242 |
+
) );
|
243 |
+
|
244 |
+
/* translators: %s: module type (plugin, theme, or add-on) */
|
245 |
+
$message .= ' ' . sprintf( fs_text_inline( 'Alternatively, you can skip it for now and activate the license later, in your %s\'s network-level Account page.', 'connect_message_network_upgrade-premium-skip-license', $slug ), $fs->get_module_label( true ) );
|
246 |
+
}else {
|
247 |
+
$message = $network_integration_text . ' ' . sprintf( fs_text_inline( 'During the update process we detected %s site(s) in the network that are still pending your attention.', 'connect_message_network_upgrade-free', $slug ), count( $sites ) ) . '<br><br>' . ( fs_starts_with( $message, $hey_x_text . '<br>' ) ? substr( $message, strlen( $hey_x_text . '<br>' ) ) : $message );
|
248 |
+
}
|
249 |
+
}
|
250 |
+
|
251 |
+
echo $message;
|
252 |
+
?></p>
|
253 |
+
<?php if ( $require_license_key ) : ?>
|
254 |
+
<div class="fs-license-key-container">
|
255 |
+
<input id="fs_license_key" name="fs_key" type="text" required maxlength="<?php echo $fs->apply_filters('license_key_maxlength', 32) ?>"
|
256 |
+
placeholder="<?php fs_esc_attr_echo_inline( 'License key', 'license-key', $slug ) ?>" tabindex="1"/>
|
257 |
+
<i class="dashicons dashicons-admin-network"></i>
|
258 |
+
<a class="show-license-resend-modal show-license-resend-modal-<?php echo $fs->get_unique_affix() ?>"
|
259 |
+
href="#"><?php fs_esc_html_echo_inline( "Can't find your license key?", 'cant-find-license-key', $slug ); ?></a>
|
260 |
+
</div>
|
261 |
+
|
262 |
+
<?php
|
263 |
+
/**
|
264 |
+
* Allows developers to include custom HTML after the license input container.
|
265 |
+
*
|
266 |
+
* @author Vova Feldman
|
267 |
+
* @since 2.1.2
|
268 |
+
*/
|
269 |
+
$fs->do_action( 'connect/after_license_input' );
|
270 |
+
?>
|
271 |
+
|
272 |
+
<?php
|
273 |
+
$send_updates_text = sprintf(
|
274 |
+
'%s<span class="action-description"> - %s</span>',
|
275 |
+
$fs->get_text_inline( 'Yes', 'yes' ),
|
276 |
+
$fs->get_text_inline( 'send me security & feature updates, educational content and offers.', 'send-updates' )
|
277 |
+
);
|
278 |
+
|
279 |
+
$do_not_send_updates_text = sprintf(
|
280 |
+
'%s<span class="action-description"> - %s</span>',
|
281 |
+
$fs->get_text_inline( 'No', 'no' ),
|
282 |
+
sprintf(
|
283 |
+
$fs->get_text_inline( 'do %sNOT%s send me security & feature updates, educational content and offers.', 'do-not-send-updates' ),
|
284 |
+
'<span class="underlined">',
|
285 |
+
'</span>'
|
286 |
+
)
|
287 |
+
);
|
288 |
+
?>
|
289 |
+
<div id="fs_marketing_optin">
|
290 |
+
<span class="fs-message"><?php fs_echo_inline( "Please let us know if you'd like us to contact you for security & feature updates, educational content, and occasional offers:", 'contact-for-updates' ) ?></span>
|
291 |
+
<div class="fs-input-container">
|
292 |
+
<label>
|
293 |
+
<input type="radio" name="allow-marketing" value="true" tabindex="1" />
|
294 |
+
<span class="fs-input-label"><?php echo $send_updates_text ?></span>
|
295 |
+
</label>
|
296 |
+
<label>
|
297 |
+
<input type="radio" name="allow-marketing" value="false" tabindex="1" />
|
298 |
+
<span class="fs-input-label"><?php echo $do_not_send_updates_text ?></span>
|
299 |
+
</label>
|
300 |
+
</div>
|
301 |
+
</div>
|
302 |
+
<?php endif ?>
|
303 |
+
<?php if ( $is_network_level_activation ) : ?>
|
304 |
+
<?php
|
305 |
+
$vars = array(
|
306 |
+
'id' => $fs->get_id(),
|
307 |
+
'sites' => $sites,
|
308 |
+
'require_license_key' => $require_license_key
|
309 |
+
);
|
310 |
+
|
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>
|
319 |
+
<?php endif ?>
|
320 |
+
<?php if ( $is_network_level_activation && $fs->apply_filters( 'show_delegation_option', true ) ) : ?>
|
321 |
+
<a id="delegate_to_site_admins" class="fs-tooltip-trigger <?php echo is_rtl() ? ' rtl' : '' ?>" href="<?php echo fs_nonce_url( $fs->_get_admin_page_url( '', array( 'fs_action' => $fs->get_unique_affix() . '_delegate_activation' ) ), $fs->get_unique_affix() . '_delegate_activation' ) ?>"><?php fs_esc_html_echo_inline( 'Delegate to Site Admins', 'delegate-to-site-admins', $slug ) ?><span class="fs-tooltip"><?php fs_esc_html_echo_inline( 'If you click it, this decision will be delegated to the sites administrators.', 'delegate-sites-tooltip', $slug ) ?></span></a>
|
322 |
+
<?php endif ?>
|
323 |
+
<?php if ( $activate_with_current_user ) : ?>
|
324 |
+
<form action="" method="POST">
|
325 |
+
<input type="hidden" name="fs_action"
|
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>
|
332 |
+
<?php else : ?>
|
333 |
+
<form method="post" action="<?php echo WP_FS__ADDRESS ?>/action/service/user/install/">
|
334 |
+
<?php unset( $optin_params['sites']); ?>
|
335 |
+
<?php foreach ( $optin_params as $name => $value ) : ?>
|
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"';
|
342 |
+
} ?>><?php echo esc_html( $button_label ) ?></button>
|
343 |
+
</form>
|
344 |
+
<?php endif ?>
|
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 ) : ?>
|
454 |
+
<div class="fs-freemium-licensing">
|
455 |
+
<p>
|
456 |
+
<?php if ( $require_license_key ) : ?>
|
457 |
+
<?php fs_esc_html_echo_inline( 'Don\'t have a license key?', 'dont-have-license-key', $slug ) ?>
|
458 |
+
<a data-require-license="false" tabindex="1"><?php fs_esc_html_echo_inline( 'Activate Free Version', 'activate-free-version', $slug ) ?></a>
|
459 |
+
<?php else : ?>
|
460 |
+
<?php fs_echo_inline( 'Have a license key?', 'have-license-key', $slug ) ?>
|
461 |
+
<a data-require-license="true" tabindex="1"><?php fs_esc_html_echo_inline( 'Activate License', 'activate-license', $slug ) ?></a>
|
462 |
+
<?php endif ?>
|
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 |
+
-
|
470 |
+
<a href="<?php echo $require_license_key ? $freemius_plugin_terms_url : $freemius_usage_tracking_url ?>" target="_blank" rel="noopener" tabindex="1"><?php $require_license_key ? fs_echo_inline( 'License Agreement', 'license-agreement', $slug ) : fs_echo_inline( 'Terms of Service', 'tos', $slug ) ?></a>
|
471 |
+
</div>
|
472 |
+
</div>
|
473 |
+
<?php
|
474 |
+
/**
|
475 |
+
* Allows developers to include custom HTML after the opt-in content.
|
476 |
+
*
|
477 |
+
* @author Vova Feldman
|
478 |
+
* @since 2.3.2
|
479 |
+
*/
|
480 |
+
$fs->do_action( 'connect/after' );
|
481 |
+
|
482 |
+
if ( $is_optin_dialog ) { ?>
|
483 |
+
</div>
|
484 |
+
<?php
|
485 |
+
}
|
486 |
+
?>
|
487 |
+
<script type="text/javascript">
|
488 |
+
(function ($) {
|
489 |
+
var $html = $('html');
|
490 |
+
|
491 |
+
<?php
|
492 |
+
if ( $is_optin_dialog ) {
|
493 |
+
if ( $show_close_button ) { ?>
|
494 |
+
var $themeConnectWrapper = $('#fs_theme_connect_wrapper');
|
495 |
+
|
496 |
+
$themeConnectWrapper.find('button.close').on('click', function () {
|
497 |
+
<?php if ( ! empty( $previous_theme_activation_url ) ) { ?>
|
498 |
+
location.href = '<?php echo html_entity_decode( $previous_theme_activation_url ); ?>';
|
499 |
+
<?php } else { ?>
|
500 |
+
$themeConnectWrapper.remove();
|
501 |
+
$html.css({overflow: $html.attr('fs-optin-overflow')});
|
502 |
+
<?php } ?>
|
503 |
+
});
|
504 |
+
<?php
|
505 |
+
}
|
506 |
+
?>
|
507 |
+
|
508 |
+
$html.attr('fs-optin-overflow', $html.css('overflow'));
|
509 |
+
$html.css({overflow: 'hidden'});
|
510 |
+
|
511 |
+
<?php
|
512 |
+
}
|
513 |
+
?>
|
514 |
+
|
515 |
+
var $primaryCta = $('.fs-actions .button.button-primary'),
|
516 |
+
primaryCtaLabel = $primaryCta.html(),
|
517 |
+
$form = $('.fs-actions form'),
|
518 |
+
isNetworkActive = <?php echo $is_network_level_activation ? 'true' : 'false' ?>,
|
519 |
+
requireLicenseKey = <?php echo $require_license_key ? 'true' : 'false' ?>,
|
520 |
+
hasContextUser = <?php echo $activate_with_current_user ? 'true' : 'false' ?>,
|
521 |
+
isNetworkUpgradeMode = <?php echo $is_network_upgrade_mode ? 'true' : 'false' ?>,
|
522 |
+
$licenseSecret,
|
523 |
+
$licenseKeyInput = $('#fs_license_key'),
|
524 |
+
pauseCtaLabelUpdate = false,
|
525 |
+
isNetworkDelegating = false,
|
526 |
+
/**
|
527 |
+
* @author Leo Fajardo (@leorw)
|
528 |
+
* @since 2.1.0
|
529 |
+
*/
|
530 |
+
resetLoadingMode = function() {
|
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 () {
|
544 |
+
setLoadingMode();
|
545 |
+
|
546 |
+
var $this = $(this);
|
547 |
+
|
548 |
+
setTimeout(function () {
|
549 |
+
if ( ! requireLicenseKey || ! $marketingOptin.hasClass( 'error' ) ) {
|
550 |
+
$this.attr('disabled', 'disabled');
|
551 |
+
}
|
552 |
+
}, 200);
|
553 |
+
});
|
554 |
+
|
555 |
+
if ( isNetworkActive ) {
|
556 |
+
var
|
557 |
+
$multisiteOptionsContainer = $( '.fs-multisite-options-container' ),
|
558 |
+
$allSitesOptions = $( '.fs-all-sites-options' ),
|
559 |
+
$applyOnAllSites = $( '.fs-apply-on-all-sites-checkbox' ),
|
560 |
+
$sitesListContainer = $( '.fs-sites-list-container' ),
|
561 |
+
totalSites = <?php echo count( $sites ) ?>,
|
562 |
+
maxSitesListHeight = null,
|
563 |
+
$skipActivationButton = $( '#skip_activation' ),
|
564 |
+
$delegateToSiteAdminsButton = $( '#delegate_to_site_admins' ),
|
565 |
+
hasAnyInstall = <?php echo ! is_null( $fs->find_first_install() ) ? 'true' : 'false' ?>;
|
566 |
+
|
567 |
+
$applyOnAllSites.click(function() {
|
568 |
+
var isChecked = $( this ).is( ':checked' );
|
569 |
+
|
570 |
+
if ( isChecked ) {
|
571 |
+
$multisiteOptionsContainer.find( '.action' ).removeClass( 'selected' );
|
572 |
+
updatePrimaryCtaText( 'allow' );
|
573 |
+
}
|
574 |
+
|
575 |
+
$multisiteOptionsContainer.find( '.action-allow' ).addClass( 'selected' );
|
576 |
+
|
577 |
+
$skipActivationButton.toggle();
|
578 |
+
|
579 |
+
$delegateToSiteAdminsButton.toggle();
|
580 |
+
|
581 |
+
$multisiteOptionsContainer.toggleClass( 'fs-apply-on-all-sites', isChecked );
|
582 |
+
|
583 |
+
$sitesListContainer.toggle( ! isChecked );
|
584 |
+
if ( ! isChecked && null === maxSitesListHeight ) {
|
585 |
+
/**
|
586 |
+
* Set the visible number of rows to 5 (5 * height of the first row).
|
587 |
+
*
|
588 |
+
* @author Leo Fajardo (@leorw)
|
589 |
+
*/
|
590 |
+
maxSitesListHeight = ( 5 * $sitesListContainer.find( 'tr:first' ).height() );
|
591 |
+
$sitesListContainer.css( 'max-height', maxSitesListHeight );
|
592 |
+
}
|
593 |
+
});
|
594 |
+
|
595 |
+
$allSitesOptions.find( '.action' ).click(function( evt ) {
|
596 |
+
var actionType = $( evt.target ).data( 'action-type' );
|
597 |
+
|
598 |
+
$multisiteOptionsContainer.find( '.action' ).removeClass( 'selected' );
|
599 |
+
$multisiteOptionsContainer.find( '.action-' + actionType ).toggleClass( 'selected' );
|
600 |
+
|
601 |
+
updatePrimaryCtaText( actionType );
|
602 |
+
});
|
603 |
+
|
604 |
+
$sitesListContainer.delegate( '.action', 'click', function( evt ) {
|
605 |
+
var $this = $( evt.target );
|
606 |
+
if ( $this.hasClass( 'selected' ) ) {
|
607 |
+
return false;
|
608 |
+
}
|
609 |
+
|
610 |
+
$this.parents( 'tr:first' ).find( '.action' ).removeClass( 'selected' );
|
611 |
+
$this.toggleClass( 'selected' );
|
612 |
+
|
613 |
+
var
|
614 |
+
singleSiteActionType = $this.data( 'action-type' ),
|
615 |
+
totalSelected = $sitesListContainer.find( '.action-' + singleSiteActionType + '.selected' ).length;
|
616 |
+
|
617 |
+
$allSitesOptions.find( '.action.selected' ).removeClass( 'selected' );
|
618 |
+
|
619 |
+
if ( totalSelected === totalSites ) {
|
620 |
+
$allSitesOptions.find( '.action-' + singleSiteActionType ).addClass( 'selected' );
|
621 |
+
|
622 |
+
updatePrimaryCtaText( singleSiteActionType );
|
623 |
+
} else {
|
624 |
+
updatePrimaryCtaText( 'mixed' );
|
625 |
+
}
|
626 |
+
});
|
627 |
+
|
628 |
+
if ( isNetworkUpgradeMode || hasAnyInstall ) {
|
629 |
+
$skipActivationButton.click(function(){
|
630 |
+
$delegateToSiteAdminsButton.hide();
|
631 |
+
|
632 |
+
$skipActivationButton.html('<?php fs_esc_js_echo_inline( 'Skipping, please wait', 'skipping-wait', $slug ) ?>...');
|
633 |
+
|
634 |
+
pauseCtaLabelUpdate = true;
|
635 |
+
|
636 |
+
// Check all sites to be skipped.
|
637 |
+
$allSitesOptions.find('.action.action-skip').click();
|
638 |
+
|
639 |
+
$form.submit();
|
640 |
+
|
641 |
+
pauseCtaLabelUpdate = false;
|
642 |
+
|
643 |
+
return false;
|
644 |
+
});
|
645 |
+
|
646 |
+
$delegateToSiteAdminsButton.click(function(){
|
647 |
+
$delegateToSiteAdminsButton.html('<?php fs_esc_js_echo_inline( 'Delegating, please wait', 'delegating-wait', $slug ) ?>...');
|
648 |
+
|
649 |
+
pauseCtaLabelUpdate = true;
|
650 |
+
|
651 |
+
/**
|
652 |
+
* Set to true so that the form submission handler can differentiate delegation from license
|
653 |
+
* activation and the proper AJAX action will be used (when delegating, the action should be
|
654 |
+
* `network_activate` and not `activate_license`).
|
655 |
+
*
|
656 |
+
* @author Leo Fajardo (@leorw)
|
657 |
+
* @since 2.3.0
|
658 |
+
*/
|
659 |
+
isNetworkDelegating = true;
|
660 |
+
|
661 |
+
// Check all sites to be skipped.
|
662 |
+
$allSitesOptions.find('.action.action-delegate').click();
|
663 |
+
|
664 |
+
$form.submit();
|
665 |
+
|
666 |
+
pauseCtaLabelUpdate = false;
|
667 |
+
|
668 |
+
/**
|
669 |
+
* Set to false so that in case the previous AJAX request has failed, the form submission handler
|
670 |
+
* can differentiate license activation from delegation and the proper AJAX action will be used
|
671 |
+
* (when activating a license, the action should be `activate_license` and not `network_activate`).
|
672 |
+
*
|
673 |
+
* @author Leo Fajardo (@leorw)
|
674 |
+
* @since 2.3.0
|
675 |
+
*/
|
676 |
+
isNetworkDelegating = false;
|
677 |
+
|
678 |
+
return false;
|
679 |
+
});
|
680 |
+
}
|
681 |
+
}
|
682 |
+
|
683 |
+
/**
|
684 |
+
* @author Leo Fajardo (@leorw)
|
685 |
+
*/
|
686 |
+
function updatePrimaryCtaText( actionType ) {
|
687 |
+
if (pauseCtaLabelUpdate)
|
688 |
+
return;
|
689 |
+
|
690 |
+
var text = '<?php fs_esc_js_echo_inline( 'Continue', 'continue', $slug ) ?>';
|
691 |
+
|
692 |
+
switch ( actionType ) {
|
693 |
+
case 'allow':
|
694 |
+
text = '<?php fs_esc_js_echo_inline( 'Allow & Continue', 'opt-in-connect', $slug ) ?>';
|
695 |
+
break;
|
696 |
+
case 'delegate':
|
697 |
+
text = '<?php fs_esc_js_echo_inline( 'Delegate to Site Admins & Continue', 'delegate-to-site-admins-and-continue', $slug ) ?>';
|
698 |
+
break;
|
699 |
+
case 'skip':
|
700 |
+
text = '<?php fs_esc_js_echo_x_inline( 'Skip', 'verb', 'skip', $slug ) ?>';
|
701 |
+
break;
|
702 |
+
}
|
703 |
+
|
704 |
+
$primaryCta.html( text );
|
705 |
+
}
|
706 |
+
|
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 |
+
/**
|
722 |
+
* @author Vova Feldman (@svovaf)
|
723 |
+
* @since 1.1.9
|
724 |
+
*/
|
725 |
+
if ( ajaxOptin ) {
|
726 |
+
if (!hasContextUser || isNetworkUpgradeMode) {
|
727 |
+
var action = null,
|
728 |
+
security = null;
|
729 |
+
|
730 |
+
if ( requireLicenseKey && ! isNetworkDelegating ) {
|
731 |
+
action = '<?php echo $fs->get_ajax_action( 'activate_license' ) ?>';
|
732 |
+
security = '<?php echo $fs->get_ajax_security( 'activate_license' ) ?>';
|
733 |
+
} else {
|
734 |
+
action = '<?php echo $fs->get_ajax_action( 'network_activate' ) ?>';
|
735 |
+
security = '<?php echo $fs->get_ajax_security( 'network_activate' ) ?>';
|
736 |
+
}
|
737 |
+
|
738 |
+
$('.fs-error').remove();
|
739 |
+
|
740 |
+
var
|
741 |
+
licenseKey = $licenseKeyInput.val(),
|
742 |
+
data = {
|
743 |
+
action : action,
|
744 |
+
security : security,
|
745 |
+
license_key: licenseKey,
|
746 |
+
module_id : '<?php echo $fs->get_id() ?>'
|
747 |
+
};
|
748 |
+
|
749 |
+
if (
|
750 |
+
requireLicenseKey &&
|
751 |
+
! isNetworkDelegating &&
|
752 |
+
isMarketingAllowedByLicense.hasOwnProperty(licenseKey)
|
753 |
+
) {
|
754 |
+
var
|
755 |
+
isMarketingAllowed = null,
|
756 |
+
$isMarketingAllowed = $marketingOptin.find( 'input[type="radio"][name="allow-marketing"]:checked');
|
757 |
+
|
758 |
+
|
759 |
+
if ($isMarketingAllowed.length > 0)
|
760 |
+
isMarketingAllowed = ('true' == $isMarketingAllowed.val());
|
761 |
+
|
762 |
+
if ( null == isMarketingAllowedByLicense[ licenseKey ] &&
|
763 |
+
null == isMarketingAllowed
|
764 |
+
) {
|
765 |
+
$marketingOptin.addClass( 'error' ).show();
|
766 |
+
resetLoadingMode();
|
767 |
+
return false;
|
768 |
+
} else if ( null == isMarketingAllowed ) {
|
769 |
+
isMarketingAllowed = isMarketingAllowedByLicense[ licenseKey ];
|
770 |
+
}
|
771 |
+
|
772 |
+
data.is_marketing_allowed = isMarketingAllowed;
|
773 |
+
|
774 |
+
data.is_extensions_tracking_allowed = isExtensionsTrackingAllowed;
|
775 |
+
}
|
776 |
+
|
777 |
+
$marketingOptin.removeClass( 'error' );
|
778 |
+
|
779 |
+
if ( isNetworkActive ) {
|
780 |
+
var
|
781 |
+
sites = [],
|
782 |
+
applyOnAllSites = $applyOnAllSites.is( ':checked' );
|
783 |
+
|
784 |
+
$sitesListContainer.find( 'tr' ).each(function() {
|
785 |
+
var
|
786 |
+
$this = $( this ),
|
787 |
+
includeSite = ( ! requireLicenseKey || applyOnAllSites || $this.find( 'input' ).is( ':checked' ) );
|
788 |
+
|
789 |
+
if ( ! includeSite )
|
790 |
+
return;
|
791 |
+
|
792 |
+
var site = {
|
793 |
+
uid : $this.find( '.uid' ).val(),
|
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 |
+
|
801 |
+
if ( ! requireLicenseKey) {
|
802 |
+
site.action = $this.find('.action.selected').data('action-type');
|
803 |
+
} else if ( isNetworkDelegating ) {
|
804 |
+
site.action = 'delegate';
|
805 |
+
}
|
806 |
+
|
807 |
+
sites.push( site );
|
808 |
+
});
|
809 |
+
|
810 |
+
data.sites = sites;
|
811 |
+
|
812 |
+
if ( hasAnyInstall ) {
|
813 |
+
data.has_any_install = hasAnyInstall;
|
814 |
+
}
|
815 |
+
}
|
816 |
+
|
817 |
+
/**
|
818 |
+
* Use the AJAX opt-in when license key is required to potentially
|
819 |
+
* process the after install failure hook.
|
820 |
+
*
|
821 |
+
* @author Vova Feldman (@svovaf)
|
822 |
+
* @since 1.2.1.5
|
823 |
+
*/
|
824 |
+
$.ajax({
|
825 |
+
url : ajaxurl,
|
826 |
+
method : 'POST',
|
827 |
+
data : data,
|
828 |
+
success: function (result) {
|
829 |
+
var resultObj = $.parseJSON(result);
|
830 |
+
if (resultObj.success) {
|
831 |
+
// Redirect to the "Account" page and sync the license.
|
832 |
+
window.location.href = resultObj.next_page;
|
833 |
+
} else {
|
834 |
+
resetLoadingMode();
|
835 |
+
|
836 |
+
// Show error.
|
837 |
+
$('.fs-content').prepend('<p class="fs-error">' + (resultObj.error.message ? resultObj.error.message : resultObj.error) + '</p>');
|
838 |
+
}
|
839 |
+
},
|
840 |
+
error: function () {
|
841 |
+
resetLoadingMode();
|
842 |
+
}
|
843 |
+
});
|
844 |
+
|
845 |
+
return false;
|
846 |
+
}
|
847 |
+
else {
|
848 |
+
if (null == $licenseSecret) {
|
849 |
+
$licenseSecret = $('<input type="hidden" name="license_secret_key" value="" />');
|
850 |
+
$form.append($licenseSecret);
|
851 |
+
}
|
852 |
+
|
853 |
+
// Update secret key if premium only plugin.
|
854 |
+
$licenseSecret.val($licenseKeyInput.val());
|
855 |
+
}
|
856 |
+
}
|
857 |
+
|
858 |
+
return true;
|
859 |
+
});
|
860 |
+
|
861 |
+
$primaryCta.on('click', function () {
|
862 |
+
console.log('Primary button was clicked');
|
863 |
+
|
864 |
+
$(this).addClass('fs-loading');
|
865 |
+
$(this).html('<?php echo esc_js( $is_pending_activation ?
|
866 |
+
fs_text_x_inline( 'Sending email', 'as in the process of sending an email', 'sending-email', $slug ) :
|
867 |
+
fs_text_x_inline( 'Activating', 'as activating plugin', 'activating', $slug )
|
868 |
+
) ?>...');
|
869 |
+
});
|
870 |
+
|
871 |
+
$('.fs-permissions .fs-trigger').on('click', function () {
|
872 |
+
$('.fs-permissions').toggleClass('fs-open');
|
873 |
+
|
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.
|
886 |
+
*
|
887 |
+
* @author Vova Feldman (@svovaf)
|
888 |
+
* @since 1.1.9
|
889 |
+
*/
|
890 |
+
$licenseKeyInput.keypress(function (e) {
|
891 |
+
if (e.which == 13) {
|
892 |
+
if ('' !== $(this).val()) {
|
893 |
+
$primaryCta.click();
|
894 |
+
return false;
|
895 |
+
}
|
896 |
+
}
|
897 |
+
});
|
898 |
+
|
899 |
+
/**
|
900 |
+
* Disable activation button when empty license key.
|
901 |
+
*
|
902 |
+
* @author Vova Feldman (@svovaf)
|
903 |
+
* @since 1.1.9
|
904 |
+
*/
|
905 |
+
$licenseKeyInput.on('keyup paste delete cut', function () {
|
906 |
+
setTimeout(function () {
|
907 |
+
var key = $licenseKeyInput.val();
|
908 |
+
|
909 |
+
if (key == previousLicenseKey){
|
910 |
+
return;
|
911 |
+
}
|
912 |
+
|
913 |
+
if ('' === key) {
|
914 |
+
$primaryCta.attr('disabled', 'disabled');
|
915 |
+
$marketingOptin.hide();
|
916 |
+
} else {
|
917 |
+
$primaryCta.prop('disabled', false);
|
918 |
+
|
919 |
+
if (32 <= key.length){
|
920 |
+
fetchIsMarketingAllowedFlagAndToggleOptin();
|
921 |
+
} else {
|
922 |
+
$marketingOptin.hide();
|
923 |
+
}
|
924 |
+
}
|
925 |
+
|
926 |
+
previousLicenseKey = key;
|
927 |
+
}, 100);
|
928 |
+
}).focus();
|
929 |
+
}
|
930 |
+
|
931 |
+
/**
|
932 |
+
* Set license mode trigger URL.
|
933 |
+
*
|
934 |
+
* @author Vova Feldman (@svovaf)
|
935 |
+
* @since 1.1.9
|
936 |
+
*/
|
937 |
+
var
|
938 |
+
$connectLicenseModeTrigger = $('#fs_connect .fs-freemium-licensing a'),
|
939 |
+
href = window.location.href;
|
940 |
+
|
941 |
+
if (href.indexOf('?') > 0) {
|
942 |
+
href += '&';
|
943 |
+
} else {
|
944 |
+
href += '?';
|
945 |
+
}
|
946 |
+
|
947 |
+
if ($connectLicenseModeTrigger.length > 0) {
|
948 |
+
$connectLicenseModeTrigger.attr(
|
949 |
+
'href',
|
950 |
+
href + 'require_license=' + $connectLicenseModeTrigger.attr('data-require-license')
|
951 |
+
);
|
952 |
+
}
|
953 |
+
|
954 |
+
//--------------------------------------------------------------------------------
|
955 |
+
//region GDPR
|
956 |
+
//--------------------------------------------------------------------------------
|
957 |
+
var isMarketingAllowedByLicense = {},
|
958 |
+
$marketingOptin = $('#fs_marketing_optin'),
|
959 |
+
previousLicenseKey = null;
|
960 |
+
|
961 |
+
if (requireLicenseKey) {
|
962 |
+
|
963 |
+
var
|
964 |
+
afterMarketingFlagLoaded = function () {
|
965 |
+
var licenseKey = $licenseKeyInput.val();
|
966 |
+
|
967 |
+
if (null == isMarketingAllowedByLicense[licenseKey]) {
|
968 |
+
$marketingOptin.show();
|
969 |
+
|
970 |
+
if ($marketingOptin.find('input[type=radio]:checked').length > 0){
|
971 |
+
// Focus on button if GDPR opt-in already selected is already selected.
|
972 |
+
$primaryCta.focus();
|
973 |
+
} else {
|
974 |
+
// Focus on the GDPR opt-in radio button.
|
975 |
+
$($marketingOptin.find('input[type=radio]')[0]).focus();
|
976 |
+
}
|
977 |
+
} else {
|
978 |
+
$marketingOptin.hide();
|
979 |
+
$primaryCta.focus();
|
980 |
+
}
|
981 |
+
},
|
982 |
+
/**
|
983 |
+
* @author Leo Fajardo (@leorw)
|
984 |
+
* @since 2.1.0
|
985 |
+
*/
|
986 |
+
fetchIsMarketingAllowedFlagAndToggleOptin = function () {
|
987 |
+
var licenseKey = $licenseKeyInput.val();
|
988 |
+
|
989 |
+
if (licenseKey.length < 32) {
|
990 |
+
$marketingOptin.hide();
|
991 |
+
return;
|
992 |
+
}
|
993 |
+
|
994 |
+
if (isMarketingAllowedByLicense.hasOwnProperty(licenseKey)) {
|
995 |
+
afterMarketingFlagLoaded();
|
996 |
+
return;
|
997 |
+
}
|
998 |
+
|
999 |
+
$marketingOptin.hide();
|
1000 |
+
|
1001 |
+
setLoadingMode();
|
1002 |
+
|
1003 |
+
$primaryCta.addClass('fs-loading');
|
1004 |
+
$primaryCta.attr('disabled', 'disabled');
|
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' ) ?>',
|
1012 |
+
security : '<?php echo $fs->get_ajax_security( 'fetch_is_marketing_required_flag_value' ) ?>',
|
1013 |
+
license_key: licenseKey,
|
1014 |
+
module_id : '<?php echo $fs->get_id() ?>'
|
1015 |
+
},
|
1016 |
+
success: function (result) {
|
1017 |
+
resetLoadingMode();
|
1018 |
+
|
1019 |
+
if (result.success) {
|
1020 |
+
result = result.data;
|
1021 |
+
|
1022 |
+
// Cache result.
|
1023 |
+
isMarketingAllowedByLicense[licenseKey] = result.is_marketing_allowed;
|
1024 |
+
}
|
1025 |
+
|
1026 |
+
afterMarketingFlagLoaded();
|
1027 |
+
}
|
1028 |
+
});
|
1029 |
+
};
|
1030 |
+
|
1031 |
+
$marketingOptin.find( 'input' ).click(function() {
|
1032 |
+
$marketingOptin.removeClass( 'error' );
|
1033 |
+
});
|
1034 |
+
}
|
1035 |
+
|
1036 |
+
//endregion
|
1037 |
+
})(jQuery);
|
1038 |
</script>
|
freemius/templates/forms/data-debug-mode.php
CHANGED
@@ -1,213 +1,213 @@
|
|
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.3.1
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var array $VARS
|
15 |
-
*
|
16 |
-
* @var Freemius $fs
|
17 |
-
*/
|
18 |
-
$fs = freemius( $VARS['id'] );
|
19 |
-
$slug = $fs->get_slug();
|
20 |
-
$unique_affix = $fs->get_unique_affix();
|
21 |
-
$last_license_user_id = $fs->get_last_license_user_id();
|
22 |
-
$has_last_license_user_id = FS_User::is_valid_id( $last_license_user_id );
|
23 |
-
|
24 |
-
$message_above_input_field = ( ! $has_last_license_user_id ) ?
|
25 |
-
fs_text_inline( 'Please enter the license key to enable the debug mode:', 'submit-developer-license-key-message', $slug ) :
|
26 |
-
sprintf(
|
27 |
-
fs_text_inline( 'To enter the debug mode, please enter the secret key of the license owner (UserID = %d), which you can find in your "My Profile" section of your User Dashboard:', 'submit-addon-developer-key-message', $slug ),
|
28 |
-
$last_license_user_id
|
29 |
-
);
|
30 |
-
|
31 |
-
$processing_text = ( fs_esc_js_inline( 'Processing', 'processing', $slug ) . '...' );
|
32 |
-
$submit_button_text = fs_text_inline( 'Submit', 'submit', $slug );
|
33 |
-
$debug_license_link_text = fs_esc_html_inline( 'Start Debug', 'start-debug-license', $slug );
|
34 |
-
$license_or_user_key_text = ( ! $has_last_license_user_id ) ?
|
35 |
-
fs_text_inline( 'License key', 'license-key' , $slug ) :
|
36 |
-
fs_text_inline( 'User key', 'user-key' , $slug );
|
37 |
-
$input_html = "<input class='fs-license-or-user-key' type='password' placeholder='{$license_or_user_key_text}' tabindex='1' />";
|
38 |
-
|
39 |
-
$modal_content_html = <<< HTML
|
40 |
-
<div class="notice notice-error inline license-or-user-key-submission-message"><p></p></div>
|
41 |
-
<p>{$message_above_input_field}</p>
|
42 |
-
{$input_html}
|
43 |
-
HTML;
|
44 |
-
|
45 |
-
fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
|
46 |
-
?>
|
47 |
-
<script type="text/javascript">
|
48 |
-
( function( $ ) {
|
49 |
-
$( document ).ready( function() {
|
50 |
-
var modalContentHtml = <?php echo json_encode( $modal_content_html ) ?>,
|
51 |
-
modalHtml =
|
52 |
-
'<div class="fs-modal fs-modal-developer-license-debug-mode fs-modal-developer-license-debug-mode-<?php echo $unique_affix ?>">'
|
53 |
-
+ ' <div class="fs-modal-dialog">'
|
54 |
-
+ ' <div class="fs-modal-body">'
|
55 |
-
+ ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'
|
56 |
-
+ ' </div>'
|
57 |
-
+ ' <div class="fs-modal-footer">'
|
58 |
-
+ ' <button class="button button-secondary button-close" tabindex="4"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></button>'
|
59 |
-
+ ' <button class="button button-primary button-submit-license-or-user-key" tabindex="3"><?php echo esc_js( $submit_button_text ) ?></button>'
|
60 |
-
+ ' </div>'
|
61 |
-
+ ' </div>'
|
62 |
-
+ '</div>',
|
63 |
-
$modal = $( modalHtml ),
|
64 |
-
$debugLicenseLink = $( '.debug-license-trigger' ),
|
65 |
-
$submitKeyButton = $modal.find( '.button-submit-license-or-user-key' ),
|
66 |
-
$licenseOrUserKeyInput = $modal.find( 'input.fs-license-or-user-key' ),
|
67 |
-
$licenseOrUserKeySubmissionMessage = $modal.find( '.license-or-user-key-submission-message' ),
|
68 |
-
isDebugMode = <?php echo $fs->is_data_debug_mode() ? 'true' : 'false' ?>;
|
69 |
-
|
70 |
-
$modal.appendTo( $( 'body' ) );
|
71 |
-
|
72 |
-
function registerEventHandlers() {
|
73 |
-
$debugLicenseLink.click(function (evt) {
|
74 |
-
evt.preventDefault();
|
75 |
-
|
76 |
-
if ( isDebugMode ) {
|
77 |
-
setDeveloperLicenseDebugMode();
|
78 |
-
return true;
|
79 |
-
}
|
80 |
-
|
81 |
-
showModal( evt );
|
82 |
-
});
|
83 |
-
|
84 |
-
$modal.on( 'input propertychange', 'input.fs-license-or-user-key', function () {
|
85 |
-
var licenseOrUserKey = $( this ).val().trim();
|
86 |
-
|
87 |
-
/**
|
88 |
-
* If license or user key is not empty, enable the submission button.
|
89 |
-
*/
|
90 |
-
if ( licenseOrUserKey.length > 0 ) {
|
91 |
-
enableSubmitButton();
|
92 |
-
}
|
93 |
-
});
|
94 |
-
|
95 |
-
$modal.on( 'blur', 'input.fs-license-or-user-key', function () {
|
96 |
-
var licenseOrUserKey = $( this ).val().trim();
|
97 |
-
|
98 |
-
/**
|
99 |
-
* If license or user key is empty, disable the submission button.
|
100 |
-
*/
|
101 |
-
if ( 0 === licenseOrUserKey.length ) {
|
102 |
-
disableSubmitButton();
|
103 |
-
}
|
104 |
-
});
|
105 |
-
|
106 |
-
$modal.on( 'click', '.button-submit-license-or-user-key', function ( evt ) {
|
107 |
-
evt.preventDefault();
|
108 |
-
|
109 |
-
if ( $( this ).hasClass( 'disabled' ) ) {
|
110 |
-
return;
|
111 |
-
}
|
112 |
-
|
113 |
-
var licenseOrUserKey = $licenseOrUserKeyInput.val().trim();
|
114 |
-
|
115 |
-
disableSubmitButton();
|
116 |
-
|
117 |
-
if ( 0 === licenseOrUserKey.length ) {
|
118 |
-
return;
|
119 |
-
}
|
120 |
-
|
121 |
-
setDeveloperLicenseDebugMode( licenseOrUserKey );
|
122 |
-
});
|
123 |
-
|
124 |
-
// If the user has clicked outside the window, close the modal.
|
125 |
-
$modal.on( 'click', '.fs-close, .button-secondary', function () {
|
126 |
-
closeModal();
|
127 |
-
return false;
|
128 |
-
} );
|
129 |
-
}
|
130 |
-
|
131 |
-
registerEventHandlers();
|
132 |
-
|
133 |
-
function setDeveloperLicenseDebugMode( licenseOrUserKey ) {
|
134 |
-
var data = {
|
135 |
-
action : '<?php echo $fs->get_ajax_action( 'set_data_debug_mode' ) ?>',
|
136 |
-
security : '<?php echo $fs->get_ajax_security( 'set_data_debug_mode' ) ?>',
|
137 |
-
license_or_user_key: licenseOrUserKey,
|
138 |
-
is_debug_mode : isDebugMode,
|
139 |
-
module_id : '<?php echo $fs->get_id() ?>'
|
140 |
-
};
|
141 |
-
|
142 |
-
$.ajax( {
|
143 |
-
url : ajaxurl,
|
144 |
-
method : 'POST',
|
145 |
-
data : data,
|
146 |
-
beforeSend: function () {
|
147 |
-
$debugLicenseLink.find('span').text( '<?php echo $processing_text ?>' );
|
148 |
-
$submitKeyButton.text( '<?php echo $processing_text ?>' );
|
149 |
-
},
|
150 |
-
success : function ( result ) {
|
151 |
-
if ( result.success ) {
|
152 |
-
closeModal();
|
153 |
-
|
154 |
-
// Reload the "Account" page so that the pricing/upgrade link will be properly hidden/shown.
|
155 |
-
window.location.reload();
|
156 |
-
} else {
|
157 |
-
showError( result.error.message ? result.error.message : result.error );
|
158 |
-
resetButtons();
|
159 |
-
}
|
160 |
-
},
|
161 |
-
error : function () {
|
162 |
-
showError( <?php echo json_encode( fs_text_inline( 'An unknown error has occurred.', 'unknown-error', $slug ) ) ?> );
|
163 |
-
resetButtons();
|
164 |
-
}
|
165 |
-
});
|
166 |
-
}
|
167 |
-
|
168 |
-
function showModal( evt ) {
|
169 |
-
resetModal();
|
170 |
-
|
171 |
-
// Display the dialog box.
|
172 |
-
$modal.addClass( 'active' );
|
173 |
-
$( 'body' ).addClass( 'has-fs-modal' );
|
174 |
-
|
175 |
-
$licenseOrUserKeyInput.val( '' );
|
176 |
-
$licenseOrUserKeyInput.focus();
|
177 |
-
}
|
178 |
-
|
179 |
-
function closeModal() {
|
180 |
-
$modal.removeClass( 'active' );
|
181 |
-
$( 'body' ).removeClass( 'has-fs-modal' );
|
182 |
-
}
|
183 |
-
|
184 |
-
function resetButtons() {
|
185 |
-
enableSubmitButton();
|
186 |
-
$submitKeyButton.text( <?php echo json_encode( $submit_button_text ) ?> );
|
187 |
-
$debugLicenseLink.find('span').text( <?php echo json_encode( $debug_license_link_text ) ?> );
|
188 |
-
}
|
189 |
-
|
190 |
-
function resetModal() {
|
191 |
-
hideError();
|
192 |
-
resetButtons();
|
193 |
-
}
|
194 |
-
|
195 |
-
function enableSubmitButton() {
|
196 |
-
$submitKeyButton.removeClass( 'disabled' );
|
197 |
-
}
|
198 |
-
|
199 |
-
function disableSubmitButton() {
|
200 |
-
$submitKeyButton.addClass( 'disabled' );
|
201 |
-
}
|
202 |
-
|
203 |
-
function hideError() {
|
204 |
-
$licenseOrUserKeySubmissionMessage.hide();
|
205 |
-
}
|
206 |
-
|
207 |
-
function showError( msg ) {
|
208 |
-
$licenseOrUserKeySubmissionMessage.find( ' > p' ).html( msg );
|
209 |
-
$licenseOrUserKeySubmissionMessage.show();
|
210 |
-
}
|
211 |
-
} );
|
212 |
-
} )( jQuery );
|
213 |
</script>
|
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.3.1
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var array $VARS
|
15 |
+
*
|
16 |
+
* @var Freemius $fs
|
17 |
+
*/
|
18 |
+
$fs = freemius( $VARS['id'] );
|
19 |
+
$slug = $fs->get_slug();
|
20 |
+
$unique_affix = $fs->get_unique_affix();
|
21 |
+
$last_license_user_id = $fs->get_last_license_user_id();
|
22 |
+
$has_last_license_user_id = FS_User::is_valid_id( $last_license_user_id );
|
23 |
+
|
24 |
+
$message_above_input_field = ( ! $has_last_license_user_id ) ?
|
25 |
+
fs_text_inline( 'Please enter the license key to enable the debug mode:', 'submit-developer-license-key-message', $slug ) :
|
26 |
+
sprintf(
|
27 |
+
fs_text_inline( 'To enter the debug mode, please enter the secret key of the license owner (UserID = %d), which you can find in your "My Profile" section of your User Dashboard:', 'submit-addon-developer-key-message', $slug ),
|
28 |
+
$last_license_user_id
|
29 |
+
);
|
30 |
+
|
31 |
+
$processing_text = ( fs_esc_js_inline( 'Processing', 'processing', $slug ) . '...' );
|
32 |
+
$submit_button_text = fs_text_inline( 'Submit', 'submit', $slug );
|
33 |
+
$debug_license_link_text = fs_esc_html_inline( 'Start Debug', 'start-debug-license', $slug );
|
34 |
+
$license_or_user_key_text = ( ! $has_last_license_user_id ) ?
|
35 |
+
fs_text_inline( 'License key', 'license-key' , $slug ) :
|
36 |
+
fs_text_inline( 'User key', 'user-key' , $slug );
|
37 |
+
$input_html = "<input class='fs-license-or-user-key' type='password' placeholder='{$license_or_user_key_text}' tabindex='1' />";
|
38 |
+
|
39 |
+
$modal_content_html = <<< HTML
|
40 |
+
<div class="notice notice-error inline license-or-user-key-submission-message"><p></p></div>
|
41 |
+
<p>{$message_above_input_field}</p>
|
42 |
+
{$input_html}
|
43 |
+
HTML;
|
44 |
+
|
45 |
+
fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
|
46 |
+
?>
|
47 |
+
<script type="text/javascript">
|
48 |
+
( function( $ ) {
|
49 |
+
$( document ).ready( function() {
|
50 |
+
var modalContentHtml = <?php echo json_encode( $modal_content_html ) ?>,
|
51 |
+
modalHtml =
|
52 |
+
'<div class="fs-modal fs-modal-developer-license-debug-mode fs-modal-developer-license-debug-mode-<?php echo $unique_affix ?>">'
|
53 |
+
+ ' <div class="fs-modal-dialog">'
|
54 |
+
+ ' <div class="fs-modal-body">'
|
55 |
+
+ ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'
|
56 |
+
+ ' </div>'
|
57 |
+
+ ' <div class="fs-modal-footer">'
|
58 |
+
+ ' <button class="button button-secondary button-close" tabindex="4"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></button>'
|
59 |
+
+ ' <button class="button button-primary button-submit-license-or-user-key" tabindex="3"><?php echo esc_js( $submit_button_text ) ?></button>'
|
60 |
+
+ ' </div>'
|
61 |
+
+ ' </div>'
|
62 |
+
+ '</div>',
|
63 |
+
$modal = $( modalHtml ),
|
64 |
+
$debugLicenseLink = $( '.debug-license-trigger' ),
|
65 |
+
$submitKeyButton = $modal.find( '.button-submit-license-or-user-key' ),
|
66 |
+
$licenseOrUserKeyInput = $modal.find( 'input.fs-license-or-user-key' ),
|
67 |
+
$licenseOrUserKeySubmissionMessage = $modal.find( '.license-or-user-key-submission-message' ),
|
68 |
+
isDebugMode = <?php echo $fs->is_data_debug_mode() ? 'true' : 'false' ?>;
|
69 |
+
|
70 |
+
$modal.appendTo( $( 'body' ) );
|
71 |
+
|
72 |
+
function registerEventHandlers() {
|
73 |
+
$debugLicenseLink.click(function (evt) {
|
74 |
+
evt.preventDefault();
|
75 |
+
|
76 |
+
if ( isDebugMode ) {
|
77 |
+
setDeveloperLicenseDebugMode();
|
78 |
+
return true;
|
79 |
+
}
|
80 |
+
|
81 |
+
showModal( evt );
|
82 |
+
});
|
83 |
+
|
84 |
+
$modal.on( 'input propertychange', 'input.fs-license-or-user-key', function () {
|
85 |
+
var licenseOrUserKey = $( this ).val().trim();
|
86 |
+
|
87 |
+
/**
|
88 |
+
* If license or user key is not empty, enable the submission button.
|
89 |
+
*/
|
90 |
+
if ( licenseOrUserKey.length > 0 ) {
|
91 |
+
enableSubmitButton();
|
92 |
+
}
|
93 |
+
});
|
94 |
+
|
95 |
+
$modal.on( 'blur', 'input.fs-license-or-user-key', function () {
|
96 |
+
var licenseOrUserKey = $( this ).val().trim();
|
97 |
+
|
98 |
+
/**
|
99 |
+
* If license or user key is empty, disable the submission button.
|
100 |
+
*/
|
101 |
+
if ( 0 === licenseOrUserKey.length ) {
|
102 |
+
disableSubmitButton();
|
103 |
+
}
|
104 |
+
});
|
105 |
+
|
106 |
+
$modal.on( 'click', '.button-submit-license-or-user-key', function ( evt ) {
|
107 |
+
evt.preventDefault();
|
108 |
+
|
109 |
+
if ( $( this ).hasClass( 'disabled' ) ) {
|
110 |
+
return;
|
111 |
+
}
|
112 |
+
|
113 |
+
var licenseOrUserKey = $licenseOrUserKeyInput.val().trim();
|
114 |
+
|
115 |
+
disableSubmitButton();
|
116 |
+
|
117 |
+
if ( 0 === licenseOrUserKey.length ) {
|
118 |
+
return;
|
119 |
+
}
|
120 |
+
|
121 |
+
setDeveloperLicenseDebugMode( licenseOrUserKey );
|
122 |
+
});
|
123 |
+
|
124 |
+
// If the user has clicked outside the window, close the modal.
|
125 |
+
$modal.on( 'click', '.fs-close, .button-secondary', function () {
|
126 |
+
closeModal();
|
127 |
+
return false;
|
128 |
+
} );
|
129 |
+
}
|
130 |
+
|
131 |
+
registerEventHandlers();
|
132 |
+
|
133 |
+
function setDeveloperLicenseDebugMode( licenseOrUserKey ) {
|
134 |
+
var data = {
|
135 |
+
action : '<?php echo $fs->get_ajax_action( 'set_data_debug_mode' ) ?>',
|
136 |
+
security : '<?php echo $fs->get_ajax_security( 'set_data_debug_mode' ) ?>',
|
137 |
+
license_or_user_key: licenseOrUserKey,
|
138 |
+
is_debug_mode : isDebugMode,
|
139 |
+
module_id : '<?php echo $fs->get_id() ?>'
|
140 |
+
};
|
141 |
+
|
142 |
+
$.ajax( {
|
143 |
+
url : ajaxurl,
|
144 |
+
method : 'POST',
|
145 |
+
data : data,
|
146 |
+
beforeSend: function () {
|
147 |
+
$debugLicenseLink.find('span').text( '<?php echo $processing_text ?>' );
|
148 |
+
$submitKeyButton.text( '<?php echo $processing_text ?>' );
|
149 |
+
},
|
150 |
+
success : function ( result ) {
|
151 |
+
if ( result.success ) {
|
152 |
+
closeModal();
|
153 |
+
|
154 |
+
// Reload the "Account" page so that the pricing/upgrade link will be properly hidden/shown.
|
155 |
+
window.location.reload();
|
156 |
+
} else {
|
157 |
+
showError( result.error.message ? result.error.message : result.error );
|
158 |
+
resetButtons();
|
159 |
+
}
|
160 |
+
},
|
161 |
+
error : function () {
|
162 |
+
showError( <?php echo json_encode( fs_text_inline( 'An unknown error has occurred.', 'unknown-error', $slug ) ) ?> );
|
163 |
+
resetButtons();
|
164 |
+
}
|
165 |
+
});
|
166 |
+
}
|
167 |
+
|
168 |
+
function showModal( evt ) {
|
169 |
+
resetModal();
|
170 |
+
|
171 |
+
// Display the dialog box.
|
172 |
+
$modal.addClass( 'active' );
|
173 |
+
$( 'body' ).addClass( 'has-fs-modal' );
|
174 |
+
|
175 |
+
$licenseOrUserKeyInput.val( '' );
|
176 |
+
$licenseOrUserKeyInput.focus();
|
177 |
+
}
|
178 |
+
|
179 |
+
function closeModal() {
|
180 |
+
$modal.removeClass( 'active' );
|
181 |
+
$( 'body' ).removeClass( 'has-fs-modal' );
|
182 |
+
}
|
183 |
+
|
184 |
+
function resetButtons() {
|
185 |
+
enableSubmitButton();
|
186 |
+
$submitKeyButton.text( <?php echo json_encode( $submit_button_text ) ?> );
|
187 |
+
$debugLicenseLink.find('span').text( <?php echo json_encode( $debug_license_link_text ) ?> );
|
188 |
+
}
|
189 |
+
|
190 |
+
function resetModal() {
|
191 |
+
hideError();
|
192 |
+
resetButtons();
|
193 |
+
}
|
194 |
+
|
195 |
+
function enableSubmitButton() {
|
196 |
+
$submitKeyButton.removeClass( 'disabled' );
|
197 |
+
}
|
198 |
+
|
199 |
+
function disableSubmitButton() {
|
200 |
+
$submitKeyButton.addClass( 'disabled' );
|
201 |
+
}
|
202 |
+
|
203 |
+
function hideError() {
|
204 |
+
$licenseOrUserKeySubmissionMessage.hide();
|
205 |
+
}
|
206 |
+
|
207 |
+
function showError( msg ) {
|
208 |
+
$licenseOrUserKeySubmissionMessage.find( ' > p' ).html( msg );
|
209 |
+
$licenseOrUserKeySubmissionMessage.show();
|
210 |
+
}
|
211 |
+
} );
|
212 |
+
} )( jQuery );
|
213 |
</script>
|
freemius/templates/forms/license-activation.php
CHANGED
@@ -1,870 +1,870 @@
|
|
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 1.1.9
|
7 |
-
*/
|
8 |
-
|
9 |
-
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
-
exit;
|
11 |
-
}
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var array $VARS
|
15 |
-
*
|
16 |
-
* @var Freemius $fs
|
17 |
-
*/
|
18 |
-
$fs = freemius( $VARS['id'] );
|
19 |
-
$slug = $fs->get_slug();
|
20 |
-
$unique_affix = $fs->get_unique_affix();
|
21 |
-
|
22 |
-
$cant_find_license_key_text = fs_text_inline( "Can't find your license key?", 'cant-find-license-key', $slug );
|
23 |
-
$message_above_input_field = fs_text_inline( 'Please enter the license key that you received in the email right after the purchase:', 'activate-license-message', $slug );
|
24 |
-
$message_below_input_field = '';
|
25 |
-
|
26 |
-
$header_title = $fs->is_free_plan() ?
|
27 |
-
fs_text_inline( 'Activate License', 'activate-license', $slug ) :
|
28 |
-
fs_text_inline( 'Update License', 'update-license', $slug );
|
29 |
-
|
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 );
|
47 |
-
}
|
48 |
-
|
49 |
-
$license_key_text = fs_text_inline( 'License key', 'license-key' , $slug );
|
50 |
-
|
51 |
-
$is_network_activation = (
|
52 |
-
$fs->is_network_active() &&
|
53 |
-
fs_is_network_admin() &&
|
54 |
-
! $fs->is_delegated_connection()
|
55 |
-
);
|
56 |
-
$network_activation_html = '';
|
57 |
-
|
58 |
-
$sites_details = array();
|
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 |
-
|
82 |
-
$network_activation_html = fs_get_template( 'partials/network-activation.php', $vars );
|
83 |
-
}
|
84 |
-
}
|
85 |
-
|
86 |
-
$premium_licenses = $fs->get_available_premium_licenses();
|
87 |
-
$available_licenses = array();
|
88 |
-
foreach ( $premium_licenses as $premium_license ) {
|
89 |
-
$activations_left = $premium_license->left();
|
90 |
-
if ( ! ( $activations_left > 0 ) ) {
|
91 |
-
continue;
|
92 |
-
}
|
93 |
-
|
94 |
-
$available_licenses[ $activations_left . '_' . $premium_license->id ] = $premium_license;
|
95 |
-
}
|
96 |
-
|
97 |
-
$total_available_licenses = count( $available_licenses );
|
98 |
-
if ( $total_available_licenses > 0 ) {
|
99 |
-
$license_input_html = <<< HTML
|
100 |
-
<div class="fs-license-options-container">
|
101 |
-
<table>
|
102 |
-
<tbody>
|
103 |
-
<tr class="fs-available-license-key-container">
|
104 |
-
<td><input type="radio" name="license_type" value="available"></td>
|
105 |
-
<td>
|
106 |
-
HTML;
|
107 |
-
|
108 |
-
if ( $total_available_licenses > 1 ) {
|
109 |
-
// Sort the licenses by number of activations left in descending order.
|
110 |
-
krsort( $available_licenses );
|
111 |
-
|
112 |
-
$license_input_html .= '<select class="fs-licenses">';
|
113 |
-
|
114 |
-
/**
|
115 |
-
* @var FS_Plugin_License $license
|
116 |
-
*/
|
117 |
-
foreach ( $available_licenses as $license ) {
|
118 |
-
$plan = $fs->_get_plan_by_id( $license->plan_id );
|
119 |
-
|
120 |
-
$label = sprintf(
|
121 |
-
"%s-Site %s License - %s",
|
122 |
-
( 1 == $license->quota ?
|
123 |
-
'Single' :
|
124 |
-
( $license->is_unlimited() ? 'Unlimited' : $license->quota )
|
125 |
-
),
|
126 |
-
( is_object( $plan ) ? $plan->title : '' ),
|
127 |
-
$license->get_html_escaped_masked_secret_key()
|
128 |
-
);
|
129 |
-
|
130 |
-
$license_input_html .= "<option data-id='{$license->id}' value='{$license->secret_key}' data-left='{$license->left()}'>{$label}</option>";
|
131 |
-
}
|
132 |
-
|
133 |
-
$license_input_html .= '</select>';
|
134 |
-
} else {
|
135 |
-
$available_licenses = array_values( $available_licenses );
|
136 |
-
|
137 |
-
/**
|
138 |
-
* @var FS_Plugin_License $available_license
|
139 |
-
*/
|
140 |
-
$available_license = $available_licenses[0];
|
141 |
-
$value = sprintf(
|
142 |
-
"%s-Site %s License - %s",
|
143 |
-
( 1 == $available_license->quota ?
|
144 |
-
'Single' :
|
145 |
-
( $available_license->is_unlimited() ? 'Unlimited' : $available_license->quota )
|
146 |
-
),
|
147 |
-
$fs->_get_plan_by_id( $available_license->plan_id )->title,
|
148 |
-
$available_license->get_html_escaped_masked_secret_key()
|
149 |
-
);
|
150 |
-
|
151 |
-
$license_input_html .= <<< HTML
|
152 |
-
<input
|
153 |
-
class="fs-available-license-key"
|
154 |
-
type="text"
|
155 |
-
value="{$value}"
|
156 |
-
data-id="{$available_license->id}"
|
157 |
-
data-license-key="{$available_license->secret_key}"
|
158 |
-
data-left="{$available_license->left()}"
|
159 |
-
readonly />
|
160 |
-
HTML;
|
161 |
-
}
|
162 |
-
|
163 |
-
$license_input_html .= <<< HTML
|
164 |
-
</td>
|
165 |
-
</tr>
|
166 |
-
<tr>
|
167 |
-
<td><input type="radio" name="license_type" value="other"></td>
|
168 |
-
<td class="fs-other-license-key-container">
|
169 |
-
<label for="other_license_key_{$unique_affix}">Other: </label>
|
170 |
-
<div>
|
171 |
-
<input id="other_license_key_{$unique_affix}" class="fs-license-key" type="text" placeholder="Enter license key" tabindex="1">
|
172 |
-
</div>
|
173 |
-
</td>
|
174 |
-
</tr>
|
175 |
-
</tbody>
|
176 |
-
</table>
|
177 |
-
</div>
|
178 |
-
HTML;
|
179 |
-
} else {
|
180 |
-
$license_input_html = "<input class='fs-license-key' type='text' placeholder='{$license_key_text}' tabindex='1' />";
|
181 |
-
}
|
182 |
-
|
183 |
-
$ownership_change_option_text = fs_text_inline( "Associate with the license owner's account.", 'associate-account-with-license-owner', $slug );
|
184 |
-
$ownership_change_option_html = "<div class='ownership-change-option-container' style='display: none'><label><input type='checkbox' /> <strong>{$ownership_change_option_text}</strong></label></div>";
|
185 |
-
|
186 |
-
/**
|
187 |
-
* IMPORTANT:
|
188 |
-
* DO NOT ADD MAXLENGTH OR LIMIT THE LICENSE KEY LENGTH SINCE
|
189 |
-
* WE DO WANT TO ALLOW INPUT OF LONGER KEYS (E.G. WooCommerce Keys)
|
190 |
-
* FOR MIGRATED MODULES.
|
191 |
-
*/
|
192 |
-
$modal_content_html = <<< HTML
|
193 |
-
<div class="notice notice-error inline license-activation-message"><p></p></div>
|
194 |
-
<p>{$message_above_input_field}</p>
|
195 |
-
{$license_input_html}
|
196 |
-
<a class="show-license-resend-modal show-license-resend-modal-{$fs->get_unique_affix()}" href="!#" tabindex="2">{$cant_find_license_key_text}</a>
|
197 |
-
{$network_activation_html}
|
198 |
-
<p>{$message_below_input_field}</p>
|
199 |
-
{$ownership_change_option_html}
|
200 |
-
HTML;
|
201 |
-
|
202 |
-
/**
|
203 |
-
* Handle the ownership change option if not an add-on or if no license yet is activated for the
|
204 |
-
* parent product in case of an add-on.
|
205 |
-
*
|
206 |
-
* @author Leo Fajardo (@leorw)
|
207 |
-
* @since 2.3.2
|
208 |
-
*/
|
209 |
-
$is_user_change_supported = ( ! $fs->is_addon() || ! $fs->get_parent_instance()->has_active_valid_license() );
|
210 |
-
|
211 |
-
fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
|
212 |
-
?>
|
213 |
-
<script type="text/javascript">
|
214 |
-
(function( $ ) {
|
215 |
-
$( document ).ready(function() {
|
216 |
-
var modalContentHtml = <?php echo json_encode($modal_content_html); ?>,
|
217 |
-
modalHtml =
|
218 |
-
'<div class="fs-modal fs-modal-license-activation fs-modal-license-activation-<?php echo $unique_affix ?>">'
|
219 |
-
+ ' <div class="fs-modal-dialog">'
|
220 |
-
+ ' <div class="fs-modal-header">'
|
221 |
-
+ ' <h4><?php echo esc_js($header_title) ?></h4>'
|
222 |
-
+ ' <a href="!#" class="fs-close"><i class="dashicons dashicons-no" title="<?php echo esc_js( fs_text_x_inline( 'Dismiss', 'as close a window', 'dismiss', $slug ) ) ?>"></i></a>'
|
223 |
-
+ ' </div>'
|
224 |
-
+ ' <div class="fs-modal-body">'
|
225 |
-
+ ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'
|
226 |
-
+ ' </div>'
|
227 |
-
+ ' <div class="fs-modal-footer">'
|
228 |
-
+ ' <button class="button button-secondary button-close" tabindex="4"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></button>'
|
229 |
-
+ ' <button class="button button-primary button-activate-license" tabindex="3"><?php echo esc_js( $activate_button_text ) ?></button>'
|
230 |
-
+ ' </div>'
|
231 |
-
+ ' </div>'
|
232 |
-
+ '</div>',
|
233 |
-
$modal = $(modalHtml),
|
234 |
-
$activateLicenseButton = $modal.find('.button-activate-license'),
|
235 |
-
$licenseKeyInput = $modal.find( 'input.fs-license-key' ),
|
236 |
-
$licenseActivationMessage = $modal.find( '.license-activation-message' ),
|
237 |
-
isNetworkActivation = <?php echo $is_network_activation ? 'true' : 'false' ?>,
|
238 |
-
isUserChangeSupported = <?php echo $is_user_change_supported ? 'true' : 'false' ?>,
|
239 |
-
isSingleSiteActivation = false,
|
240 |
-
$ownershipChangeOptionContainer = $modal.find( '.ownership-change-option-container' ),
|
241 |
-
$body = $( 'body' );
|
242 |
-
|
243 |
-
$modal.appendTo( $body );
|
244 |
-
|
245 |
-
var
|
246 |
-
$licensesDropdown = $modal.find( '.fs-licenses' ),
|
247 |
-
$licenseTypes = $modal.find( 'input[type="radio"][name="license_type"]' ),
|
248 |
-
$applyOnAllSites = $modal.find( '.fs-apply-on-all-sites-checkbox' ),
|
249 |
-
$sitesListContainer = $modal.find( '.fs-sites-list-container' ),
|
250 |
-
$availableLicenseKey = $modal.find( '.fs-available-license-key' ),
|
251 |
-
$otherLicenseKey = $modal.find( '#other_license_key_<?php echo $unique_affix ?>' ),
|
252 |
-
$multisiteOptionsContainer = $modal.find( '.fs-multisite-options-container' ),
|
253 |
-
$activationsLeft = null,
|
254 |
-
hasLicensesDropdown = ( $licensesDropdown.length > 0 ),
|
255 |
-
hasLicenseTypes = ( $licenseTypes.length > 0 ),
|
256 |
-
maxSitesListHeight = null,
|
257 |
-
totalSites = <?php echo count( $sites_details ) ?>,
|
258 |
-
singleBlogID = null;
|
259 |
-
|
260 |
-
var
|
261 |
-
previousLicenseKey = null,
|
262 |
-
otherLicenseOwnerID = null,
|
263 |
-
/**
|
264 |
-
* @author Leo Fajardo (@leorw)
|
265 |
-
* @since 2.3.2
|
266 |
-
*/
|
267 |
-
resetLoadingMode = function () {
|
268 |
-
// Reset loading mode.
|
269 |
-
$activateLicenseButton.text( <?php echo json_encode( $activate_button_text ) ?> );
|
270 |
-
$activateLicenseButton.prop( 'disabled', false );
|
271 |
-
$( document.body ).css( { 'cursor': 'auto' } );
|
272 |
-
$( '.fs-loading' ).removeClass( 'fs-loading' );
|
273 |
-
|
274 |
-
console.log( 'resetLoadingMode - Primary button was enabled' );
|
275 |
-
},
|
276 |
-
/**
|
277 |
-
* @author Leo Fajardo (@leorw)
|
278 |
-
* @since 2.3.2
|
279 |
-
*/
|
280 |
-
setLoadingMode = function () {
|
281 |
-
$( document.body ).css( { 'cursor': 'wait' } );
|
282 |
-
},
|
283 |
-
/**
|
284 |
-
* @author Leo Fajardo (@leorw)
|
285 |
-
* @since 2.3.2
|
286 |
-
*/
|
287 |
-
afterLicenseUserDataLoaded = function () {
|
288 |
-
if (
|
289 |
-
null !== otherLicenseOwnerID &&
|
290 |
-
otherLicenseOwnerID != <?php echo $fs->is_registered() ? $fs->get_user()->id : 'null' ?>
|
291 |
-
) {
|
292 |
-
$ownershipChangeOptionContainer.show();
|
293 |
-
} else {
|
294 |
-
$ownershipChangeOptionContainer.hide();
|
295 |
-
$activateLicenseButton.focus();
|
296 |
-
}
|
297 |
-
},
|
298 |
-
/**
|
299 |
-
* @author Leo Fajardo (@leorw)
|
300 |
-
* @since 2.3.2
|
301 |
-
*/
|
302 |
-
fetchLicenseUserData = function () {
|
303 |
-
var hideAndUncheckUserChangeCheckbox = ( ! isUserChangeSupported ),
|
304 |
-
otherLicenseKeyIsSelected = isOtherLicenseKeySelected();
|
305 |
-
|
306 |
-
if ( ! hideAndUncheckUserChangeCheckbox ) {
|
307 |
-
// User change is supported only on the site level.
|
308 |
-
hideAndUncheckUserChangeCheckbox = ( isNetworkActivation || isSingleSiteActivation );
|
309 |
-
}
|
310 |
-
|
311 |
-
if ( ! hideAndUncheckUserChangeCheckbox ) {
|
312 |
-
hideAndUncheckUserChangeCheckbox = ( hasLicenseTypes && ! otherLicenseKeyIsSelected );
|
313 |
-
}
|
314 |
-
|
315 |
-
var licenseKey = $licenseKeyInput.val().trim();
|
316 |
-
|
317 |
-
if ( ! hideAndUncheckUserChangeCheckbox && otherLicenseKeyIsSelected ) {
|
318 |
-
hideAndUncheckUserChangeCheckbox = ( licenseKey.length < 32 );
|
319 |
-
}
|
320 |
-
|
321 |
-
if ( licenseKey !== previousLicenseKey ) {
|
322 |
-
// If the license key has not been changed, keep the owner ID in order to prevent another API call.
|
323 |
-
otherLicenseOwnerID = null;
|
324 |
-
}
|
325 |
-
|
326 |
-
if ( hideAndUncheckUserChangeCheckbox ) {
|
327 |
-
$ownershipChangeOptionContainer.hide().find( 'input' ).attr( 'checked', false );
|
328 |
-
|
329 |
-
return;
|
330 |
-
}
|
331 |
-
|
332 |
-
if ( null !== otherLicenseOwnerID ) {
|
333 |
-
afterLicenseUserDataLoaded();
|
334 |
-
return;
|
335 |
-
}
|
336 |
-
|
337 |
-
setLoadingMode();
|
338 |
-
|
339 |
-
$activateLicenseButton.addClass( 'fs-loading' );
|
340 |
-
$activateLicenseButton.attr( 'disabled', 'disabled' );
|
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' ) ?>',
|
348 |
-
security : '<?php echo $fs->get_ajax_security( 'fetch_is_marketing_required_flag_value' ) ?>',
|
349 |
-
license_key: licenseKey,
|
350 |
-
module_id : '<?php echo $fs->get_id() ?>'
|
351 |
-
},
|
352 |
-
success: function ( result ) {
|
353 |
-
resetLoadingMode();
|
354 |
-
|
355 |
-
if ( result.success ) {
|
356 |
-
result = result.data;
|
357 |
-
|
358 |
-
// Cache license owner's ID.
|
359 |
-
otherLicenseOwnerID = result.license_owner_id;
|
360 |
-
}
|
361 |
-
|
362 |
-
afterLicenseUserDataLoaded();
|
363 |
-
}
|
364 |
-
} );
|
365 |
-
};
|
366 |
-
|
367 |
-
function registerEventHandlers() {
|
368 |
-
var
|
369 |
-
$otherLicenseKeyContainer = $modal.find( '.fs-other-license-key-container' );
|
370 |
-
|
371 |
-
if ( isNetworkActivation ) {
|
372 |
-
$applyOnAllSites.click(function() {
|
373 |
-
var applyOnAllSites = $( this ).is( ':checked' );
|
374 |
-
|
375 |
-
$multisiteOptionsContainer.toggleClass( 'fs-apply-on-all-sites', applyOnAllSites );
|
376 |
-
|
377 |
-
showSites( ! applyOnAllSites );
|
378 |
-
|
379 |
-
if ( hasValidLicenseKey() && ( applyOnAllSites || hasSelectedSite() ) ) {
|
380 |
-
enableActivateLicenseButton();
|
381 |
-
} else {
|
382 |
-
disableActivateLicenseButton();
|
383 |
-
}
|
384 |
-
});
|
385 |
-
|
386 |
-
$sitesListContainer.delegate( 'td:not(:first-child)', 'click', function() {
|
387 |
-
// If a site row is clicked, trigger a click on the checkbox.
|
388 |
-
$( this ).parent().find( 'td:first-child input' ).click();
|
389 |
-
});
|
390 |
-
|
391 |
-
$sitesListContainer.delegate( 'input[type="checkbox"]', 'click', function() {
|
392 |
-
enableDisableSitesSelection();
|
393 |
-
|
394 |
-
if ( hasValidLicenseKey() && hasSelectedSite() ) {
|
395 |
-
enableActivateLicenseButton();
|
396 |
-
} else {
|
397 |
-
disableActivateLicenseButton();
|
398 |
-
}
|
399 |
-
});
|
400 |
-
}
|
401 |
-
|
402 |
-
if ( hasLicensesDropdown ) {
|
403 |
-
$licensesDropdown.change(function() {
|
404 |
-
// When a license is selected, select the associated radio button.
|
405 |
-
$licenseTypes.filter( '[value="available"]' ).attr( 'checked', true );
|
406 |
-
|
407 |
-
if ( ! isNetworkActivation || $modal.hasClass( 'is-single-site-activation' ) ) {
|
408 |
-
enableActivateLicenseButton();
|
409 |
-
return true;
|
410 |
-
}
|
411 |
-
|
412 |
-
toggleActivationOnAllSites();
|
413 |
-
})
|
414 |
-
}
|
415 |
-
|
416 |
-
if ( hasLicenseTypes ) {
|
417 |
-
$licenseTypes.change(function() {
|
418 |
-
var
|
419 |
-
licenseKey = $modal.find( 'input.fs-license-key' ).val().trim(),
|
420 |
-
otherLicenseKeySelected = isOtherLicenseKeySelected();
|
421 |
-
|
422 |
-
if ( ( licenseKey.length > 0 || ( hasLicenseTypes && ! otherLicenseKeySelected ) ) &&
|
423 |
-
( $modal.hasClass( 'is-single-site-activation' ) || ! isNetworkActivation || hasSelectedSite() )
|
424 |
-
) {
|
425 |
-
/**
|
426 |
-
* If the "other" license is not empty or an available license is selected, enable the activate
|
427 |
-
* button.
|
428 |
-
*
|
429 |
-
* @author Leo Fajardo (@leorw)
|
430 |
-
*/
|
431 |
-
enableActivateLicenseButton();
|
432 |
-
} else {
|
433 |
-
disableActivateLicenseButton();
|
434 |
-
}
|
435 |
-
|
436 |
-
if ( '' !== licenseKey ) {
|
437 |
-
fetchLicenseUserData();
|
438 |
-
}
|
439 |
-
|
440 |
-
if ( ! isNetworkActivation ) {
|
441 |
-
return;
|
442 |
-
}
|
443 |
-
|
444 |
-
if ( otherLicenseKeySelected ) {
|
445 |
-
$applyOnAllSites.attr( 'disabled', false );
|
446 |
-
enableDisableSitesSelection();
|
447 |
-
resetActivateLicenseCheckboxLabel();
|
448 |
-
} else if ( ! $modal.hasClass( 'is-single-site-activation' ) ) {
|
449 |
-
toggleActivationOnAllSites();
|
450 |
-
}
|
451 |
-
});
|
452 |
-
|
453 |
-
if ( ! hasLicensesDropdown ) {
|
454 |
-
$availableLicenseKey.click(function() {
|
455 |
-
$licenseTypes.filter( '[value="available"]' ).click();
|
456 |
-
});
|
457 |
-
}
|
458 |
-
|
459 |
-
$otherLicenseKeyContainer.click(function() {
|
460 |
-
$licenseTypes.filter( '[value="other"]' ).click();
|
461 |
-
});
|
462 |
-
}
|
463 |
-
|
464 |
-
$body.on( 'click', 'span.activate-license.<?php echo $unique_affix ?> a, .activate-license-trigger.<?php echo $unique_affix ?>', function (evt) {
|
465 |
-
evt.preventDefault();
|
466 |
-
|
467 |
-
showModal( evt );
|
468 |
-
});
|
469 |
-
|
470 |
-
var licenseTimeout = null;
|
471 |
-
|
472 |
-
/**
|
473 |
-
* Disable activation button when license key is empty.
|
474 |
-
*
|
475 |
-
* @author Leo Fajardo (@leorw)
|
476 |
-
* @since 2.3.2
|
477 |
-
*/
|
478 |
-
$modal.on( 'keyup paste delete cut', 'input.fs-license-key', function () {
|
479 |
-
clearTimeout(licenseTimeout);
|
480 |
-
|
481 |
-
licenseTimeout = setTimeout( function () {
|
482 |
-
var licenseKey = $licenseKeyInput.val().trim();
|
483 |
-
|
484 |
-
if ( licenseKey == previousLicenseKey ) {
|
485 |
-
afterLicenseUserDataLoaded();
|
486 |
-
return;
|
487 |
-
}
|
488 |
-
|
489 |
-
if ( '' === licenseKey ) {
|
490 |
-
disableActivateLicenseButton();
|
491 |
-
$ownershipChangeOptionContainer.hide();
|
492 |
-
} else {
|
493 |
-
enableActivateLicenseButton();
|
494 |
-
|
495 |
-
if ( 32 <= licenseKey.length ) {
|
496 |
-
fetchLicenseUserData();
|
497 |
-
} else {
|
498 |
-
$ownershipChangeOptionContainer.hide();
|
499 |
-
}
|
500 |
-
}
|
501 |
-
|
502 |
-
previousLicenseKey = licenseKey;
|
503 |
-
}, 200 );
|
504 |
-
} ).focus();
|
505 |
-
|
506 |
-
$modal.on('input propertychange', 'input.fs-license-key', function () {
|
507 |
-
|
508 |
-
var licenseKey = $(this).val().trim();
|
509 |
-
|
510 |
-
/**
|
511 |
-
* If license key is not empty, enable the license activation button.
|
512 |
-
*/
|
513 |
-
if ( licenseKey.length > 0 && ( $modal.hasClass( 'is-single-site-activation' ) || ! isNetworkActivation || hasSelectedSite() ) ) {
|
514 |
-
enableActivateLicenseButton();
|
515 |
-
}
|
516 |
-
});
|
517 |
-
|
518 |
-
$modal.on( 'blur', 'input.fs-license-key', function( evt ) {
|
519 |
-
var
|
520 |
-
licenseKey = $(this).val().trim(),
|
521 |
-
$focusedElement = $( evt.relatedTarget ),
|
522 |
-
hasSelectedAvailableLicense = ( hasLicenseTypes && $focusedElement.parents( '.fs-available-license-key-container' ).length > 0 );
|
523 |
-
|
524 |
-
/**
|
525 |
-
* If license key is empty, disable the license activation button.
|
526 |
-
*/
|
527 |
-
if ( ( 0 === licenseKey.length && ( ! hasLicenseTypes || ! hasSelectedAvailableLicense ) ) ||
|
528 |
-
( isNetworkActivation && ! hasSelectedSite() )
|
529 |
-
) {
|
530 |
-
disableActivateLicenseButton();
|
531 |
-
}
|
532 |
-
});
|
533 |
-
|
534 |
-
$modal.on('click', '.button-activate-license', function (evt) {
|
535 |
-
evt.preventDefault();
|
536 |
-
|
537 |
-
if ($(this).hasClass('disabled')) {
|
538 |
-
return;
|
539 |
-
}
|
540 |
-
|
541 |
-
var
|
542 |
-
licenseKey = '';
|
543 |
-
|
544 |
-
if ( hasLicenseTypes ) {
|
545 |
-
if ( isOtherLicenseKeySelected() ) {
|
546 |
-
licenseKey = $otherLicenseKey.val();
|
547 |
-
} else {
|
548 |
-
if ( ! hasLicensesDropdown ) {
|
549 |
-
licenseKey = $availableLicenseKey.data( 'license-key' );
|
550 |
-
} else {
|
551 |
-
licenseKey = $licensesDropdown.val();
|
552 |
-
}
|
553 |
-
}
|
554 |
-
} else {
|
555 |
-
licenseKey = $licenseKeyInput.val().trim();
|
556 |
-
}
|
557 |
-
|
558 |
-
disableActivateLicenseButton();
|
559 |
-
|
560 |
-
if (0 === licenseKey.length) {
|
561 |
-
return;
|
562 |
-
}
|
563 |
-
|
564 |
-
var data = {
|
565 |
-
action : '<?php echo $fs->get_ajax_action( 'activate_license' ) ?>',
|
566 |
-
security : '<?php echo $fs->get_ajax_security( 'activate_license' ) ?>',
|
567 |
-
license_key: licenseKey,
|
568 |
-
module_id : '<?php echo $fs->get_id() ?>'
|
569 |
-
};
|
570 |
-
|
571 |
-
if ( isNetworkActivation ) {
|
572 |
-
var
|
573 |
-
sites = [];
|
574 |
-
|
575 |
-
if ( null === singleBlogID ) {
|
576 |
-
var
|
577 |
-
applyOnAllSites = $applyOnAllSites.is( ':checked' );
|
578 |
-
|
579 |
-
$sitesListContainer.find( 'tr' ).each(function() {
|
580 |
-
var
|
581 |
-
|
582 |
-
includeSite = ( applyOnAllSites || $this.find( 'input' ).is( ':checked' ) );
|
583 |
-
|
584 |
-
if ( ! includeSite )
|
585 |
-
return;
|
586 |
-
|
587 |
-
var site = {
|
588 |
-
uid : $this.find( '.uid' ).val(),
|
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 |
-
|
596 |
-
sites.push( site );
|
597 |
-
});
|
598 |
-
} else {
|
599 |
-
data.blog_id = singleBlogID;
|
600 |
-
}
|
601 |
-
|
602 |
-
data.sites = sites;
|
603 |
-
}
|
604 |
-
|
605 |
-
if ( $ownershipChangeOptionContainer.find( 'input:checked' ).length > 0 ) {
|
606 |
-
data.user_id = otherLicenseOwnerID;
|
607 |
-
}
|
608 |
-
|
609 |
-
$.ajax({
|
610 |
-
url: ajaxurl,
|
611 |
-
method: 'POST',
|
612 |
-
data: data,
|
613 |
-
beforeSend: function () {
|
614 |
-
$activateLicenseButton.text( '<?php fs_esc_js_echo_inline( 'Activating license', 'activating-license', $slug ) ?>...' );
|
615 |
-
},
|
616 |
-
success: function( result ) {
|
617 |
-
var resultObj = $.parseJSON( result );
|
618 |
-
if ( resultObj.success ) {
|
619 |
-
closeModal();
|
620 |
-
|
621 |
-
// Redirect to the "Account" page and sync the license.
|
622 |
-
window.location.href = resultObj.next_page;
|
623 |
-
} else {
|
624 |
-
showError( resultObj.error.message ? resultObj.error.message : resultObj.error );
|
625 |
-
resetActivateLicenseButton();
|
626 |
-
}
|
627 |
-
}
|
628 |
-
});
|
629 |
-
});
|
630 |
-
|
631 |
-
// If the user has clicked outside the window, close the modal.
|
632 |
-
$modal.on('click', '.fs-close, .button-secondary', function () {
|
633 |
-
closeModal();
|
634 |
-
return false;
|
635 |
-
});
|
636 |
-
}
|
637 |
-
|
638 |
-
registerEventHandlers();
|
639 |
-
|
640 |
-
$body.trigger('licenseActivationLoaded');
|
641 |
-
|
642 |
-
/**
|
643 |
-
* @author Leo Fajardo (@leorw)
|
644 |
-
* @since 2.0.0
|
645 |
-
*/
|
646 |
-
function enableDisableSitesSelection() {
|
647 |
-
var
|
648 |
-
canApplyOnAllSites = $applyOnAllSites.is( ':enabled' ),
|
649 |
-
disableSitesSelection = null;
|
650 |
-
|
651 |
-
if ( ! canApplyOnAllSites ) {
|
652 |
-
var
|
653 |
-
selectedSites = $sitesListContainer.find( 'input[type="checkbox"]:checked' ).length,
|
654 |
-
activationsLeft = Math.max( 0, $activationsLeft.data( 'left' ) - selectedSites );
|
655 |
-
|
656 |
-
disableSitesSelection = ( 0 === activationsLeft );
|
657 |
-
|
658 |
-
$activationsLeft.text( activationsLeft );
|
659 |
-
} else {
|
660 |
-
disableSitesSelection = false;
|
661 |
-
}
|
662 |
-
|
663 |
-
$sitesListContainer
|
664 |
-
.find( 'input[type="checkbox"]:not(:checked)' )
|
665 |
-
.attr( 'disabled', disableSitesSelection );
|
666 |
-
}
|
667 |
-
|
668 |
-
/**
|
669 |
-
* @author Leo Fajardo (@leorw)
|
670 |
-
* @since 2.0.0
|
671 |
-
*
|
672 |
-
* @returns {Boolean}
|
673 |
-
*/
|
674 |
-
function isOtherLicenseKeySelected() {
|
675 |
-
return ( hasLicenseTypes && 'other' === $licenseTypes.filter( ':checked' ).val() );
|
676 |
-
}
|
677 |
-
|
678 |
-
/**
|
679 |
-
* @author Leo Fajardo (@leorw)
|
680 |
-
* @since 2.0.0
|
681 |
-
*
|
682 |
-
* @returns {Boolean}
|
683 |
-
*/
|
684 |
-
function hasValidLicenseKey() {
|
685 |
-
var licenseKey = '';
|
686 |
-
if ( hasLicenseTypes ) {
|
687 |
-
if ( 'available' === $licenseTypes.filter( ':checked' ).val() ) {
|
688 |
-
return true;
|
689 |
-
} else {
|
690 |
-
licenseKey = $otherLicenseKey.val();
|
691 |
-
}
|
692 |
-
} else {
|
693 |
-
licenseKey = $modal.find( 'input.fs-license-key' ).val();
|
694 |
-
}
|
695 |
-
|
696 |
-
return ( licenseKey.trim().length > 0 );
|
697 |
-
}
|
698 |
-
|
699 |
-
/**
|
700 |
-
* @author Leo Fajardo (@leorw)
|
701 |
-
* @since 2.0.0
|
702 |
-
*
|
703 |
-
* @returns {Boolean}
|
704 |
-
*/
|
705 |
-
function hasSelectedSite() {
|
706 |
-
return ( $applyOnAllSites.is( ':checked' ) ||
|
707 |
-
$sitesListContainer.find( 'input[type="checkbox"]:checked:not(:disabled)' ).length > 0 );
|
708 |
-
}
|
709 |
-
|
710 |
-
/**
|
711 |
-
* @author Leo Fajardo (@leorw)
|
712 |
-
* @since 2.0.0
|
713 |
-
*/
|
714 |
-
function toggleActivationOnAllSites() {
|
715 |
-
var activationsLeft,
|
716 |
-
licenseID;
|
717 |
-
|
718 |
-
if (hasLicensesDropdown) {
|
719 |
-
var $selectedOption = $licensesDropdown.find( ':selected' );
|
720 |
-
activationsLeft = $selectedOption.data('left');
|
721 |
-
licenseID = $selectedOption.data('id');
|
722 |
-
} else {
|
723 |
-
activationsLeft = $availableLicenseKey.data('left');
|
724 |
-
licenseID = $availableLicenseKey.data('id');
|
725 |
-
}
|
726 |
-
|
727 |
-
// Cleanup previously auto-selected site.
|
728 |
-
$modal.find( '.fs-sites-list-container input[type=checkbox]:disabled' )
|
729 |
-
.attr('disabled', false)
|
730 |
-
.attr('checked', false);
|
731 |
-
|
732 |
-
var $blogsWithActiveLicense = $modal.find( '.fs-sites-list-container tr[data-license-id=' + licenseID + '] input[type=checkbox]' );
|
733 |
-
|
734 |
-
if ($blogsWithActiveLicense.length > 0) {
|
735 |
-
$blogsWithActiveLicense.attr('checked', true)
|
736 |
-
.attr('disabled', true);
|
737 |
-
|
738 |
-
activationsLeft += $blogsWithActiveLicense.length;
|
739 |
-
}
|
740 |
-
|
741 |
-
if ( activationsLeft >= totalSites ) {
|
742 |
-
$applyOnAllSites.attr( 'disabled', false );
|
743 |
-
enableDisableSitesSelection();
|
744 |
-
|
745 |
-
resetActivateLicenseCheckboxLabel();
|
746 |
-
|
747 |
-
return;
|
748 |
-
}
|
749 |
-
|
750 |
-
$applyOnAllSites.attr( 'checked', false );
|
751 |
-
$applyOnAllSites.attr( 'disabled', true );
|
752 |
-
|
753 |
-
showSites( true );
|
754 |
-
|
755 |
-
var
|
756 |
-
activateLicenseCheckboxLabel = '<?php fs_esc_js_echo_inline( 'Choose up to %s site(s) to activate the license on.', 'choose-up-to-n-sites-to-activate-the-license-on', $slug ) ?>';
|
757 |
-
|
758 |
-
activateLicenseCheckboxLabel = activateLicenseCheckboxLabel.replace( '%s', '<span data-left="' + activationsLeft + '" class="activations-left">' + activationsLeft + '</span>' );
|
759 |
-
|
760 |
-
// Update the label of the "Activate license on all sites" checkbox.
|
761 |
-
$applyOnAllSites.parent().find( 'span' ).html( activateLicenseCheckboxLabel );
|
762 |
-
$activationsLeft = $modal.find( '.activations-left' );
|
763 |
-
|
764 |
-
if ( hasSelectedSite() ) {
|
765 |
-
enableActivateLicenseButton();
|
766 |
-
enableDisableSitesSelection();
|
767 |
-
} else {
|
768 |
-
disableActivateLicenseButton();
|
769 |
-
}
|
770 |
-
}
|
771 |
-
|
772 |
-
/**
|
773 |
-
* @author Leo Fajardo (@leorw)
|
774 |
-
* @since 2.0.0
|
775 |
-
*/
|
776 |
-
function resetActivateLicenseCheckboxLabel() {
|
777 |
-
var activateLicenseCheckboxLabel = '<?php fs_esc_js_echo_inline( 'Activate license on all sites in the network.', 'activate-license-on-all-sites-in-the-network', $slug ) ?>';
|
778 |
-
$applyOnAllSites.parent().find( 'span' ).text( activateLicenseCheckboxLabel );
|
779 |
-
}
|
780 |
-
|
781 |
-
/**
|
782 |
-
* @author Leo Fajardo (@leorw)
|
783 |
-
* @since 2.0.0
|
784 |
-
*
|
785 |
-
* @param {Boolean} show
|
786 |
-
*/
|
787 |
-
function showSites( show ) {
|
788 |
-
$sitesListContainer.toggle( show );
|
789 |
-
if ( show && null === maxSitesListHeight ) {
|
790 |
-
/**
|
791 |
-
* Set the visible number of rows to 5 (5 * height of the first row).
|
792 |
-
*
|
793 |
-
* @author Leo Fajardo (@leorw)
|
794 |
-
*/
|
795 |
-
maxSitesListHeight = ( 5 * $sitesListContainer.find( 'tr:first' ).height() );
|
796 |
-
$sitesListContainer.css( 'max-height', maxSitesListHeight );
|
797 |
-
}
|
798 |
-
}
|
799 |
-
|
800 |
-
function showModal( evt ) {
|
801 |
-
resetModal();
|
802 |
-
|
803 |
-
// Display the dialog box.
|
804 |
-
$modal.addClass('active');
|
805 |
-
$body.addClass('has-fs-modal');
|
806 |
-
|
807 |
-
var
|
808 |
-
$singleInstallDetails = $( evt.target ).parents( 'tr.fs-install-details' ),
|
809 |
-
isSingleSiteActivation = ( $singleInstallDetails.length > 0 );
|
810 |
-
|
811 |
-
$modal.toggleClass( 'is-single-site-activation', isSingleSiteActivation );
|
812 |
-
|
813 |
-
singleBlogID = isSingleSiteActivation ?
|
814 |
-
$singleInstallDetails.prev().data( 'blog-id' ) :
|
815 |
-
null;
|
816 |
-
|
817 |
-
<?php if ( $fs->apply_filters( 'enable_per_site_activation', true ) ) : ?>
|
818 |
-
$multisiteOptionsContainer.toggle( isNetworkActivation && ! isSingleSiteActivation );
|
819 |
-
<?php endif ?>
|
820 |
-
|
821 |
-
if ( hasLicenseTypes ) {
|
822 |
-
$licenseTypes.attr( 'checked', false );
|
823 |
-
|
824 |
-
if ( hasLicensesDropdown ) {
|
825 |
-
$licensesDropdown.find( 'option:first' ).attr( 'selected', true ).trigger( 'change' );
|
826 |
-
} else {
|
827 |
-
$licenseTypes.filter( '[value="available"]' ).click();
|
828 |
-
}
|
829 |
-
|
830 |
-
$otherLicenseKey.val( '' );
|
831 |
-
} else {
|
832 |
-
$licenseKeyInput.val( '' );
|
833 |
-
$licenseKeyInput.focus();
|
834 |
-
}
|
835 |
-
}
|
836 |
-
|
837 |
-
function closeModal() {
|
838 |
-
$modal.removeClass('active');
|
839 |
-
$body.removeClass('has-fs-modal');
|
840 |
-
}
|
841 |
-
|
842 |
-
function resetActivateLicenseButton() {
|
843 |
-
enableActivateLicenseButton();
|
844 |
-
$activateLicenseButton.text( <?php echo json_encode( $activate_button_text ) ?> );
|
845 |
-
}
|
846 |
-
|
847 |
-
function resetModal() {
|
848 |
-
hideError();
|
849 |
-
resetActivateLicenseButton();
|
850 |
-
}
|
851 |
-
|
852 |
-
function enableActivateLicenseButton() {
|
853 |
-
$activateLicenseButton.removeClass( 'disabled' );
|
854 |
-
}
|
855 |
-
|
856 |
-
function disableActivateLicenseButton() {
|
857 |
-
$activateLicenseButton.addClass( 'disabled' );
|
858 |
-
}
|
859 |
-
|
860 |
-
function hideError() {
|
861 |
-
$licenseActivationMessage.hide();
|
862 |
-
}
|
863 |
-
|
864 |
-
function showError( msg ) {
|
865 |
-
$licenseActivationMessage.find( ' > p' ).html( msg );
|
866 |
-
$licenseActivationMessage.show();
|
867 |
-
}
|
868 |
-
});
|
869 |
-
})( jQuery );
|
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 1.1.9
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
10 |
+
exit;
|
11 |
+
}
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var array $VARS
|
15 |
+
*
|
16 |
+
* @var Freemius $fs
|
17 |
+
*/
|
18 |
+
$fs = freemius( $VARS['id'] );
|
19 |
+
$slug = $fs->get_slug();
|
20 |
+
$unique_affix = $fs->get_unique_affix();
|
21 |
+
|
22 |
+
$cant_find_license_key_text = fs_text_inline( "Can't find your license key?", 'cant-find-license-key', $slug );
|
23 |
+
$message_above_input_field = fs_text_inline( 'Please enter the license key that you received in the email right after the purchase:', 'activate-license-message', $slug );
|
24 |
+
$message_below_input_field = '';
|
25 |
+
|
26 |
+
$header_title = $fs->is_free_plan() ?
|
27 |
+
fs_text_inline( 'Activate License', 'activate-license', $slug ) :
|
28 |
+
fs_text_inline( 'Update License', 'update-license', $slug );
|
29 |
+
|
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 );
|
47 |
+
}
|
48 |
+
|
49 |
+
$license_key_text = fs_text_inline( 'License key', 'license-key' , $slug );
|
50 |
+
|
51 |
+
$is_network_activation = (
|
52 |
+
$fs->is_network_active() &&
|
53 |
+
fs_is_network_admin() &&
|
54 |
+
! $fs->is_delegated_connection()
|
55 |
+
);
|
56 |
+
$network_activation_html = '';
|
57 |
+
|
58 |
+
$sites_details = array();
|
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 |
+
|
82 |
+
$network_activation_html = fs_get_template( 'partials/network-activation.php', $vars );
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
$premium_licenses = $fs->get_available_premium_licenses();
|
87 |
+
$available_licenses = array();
|
88 |
+
foreach ( $premium_licenses as $premium_license ) {
|
89 |
+
$activations_left = $premium_license->left();
|
90 |
+
if ( ! ( $activations_left > 0 ) ) {
|
91 |
+
continue;
|
92 |
+
}
|
93 |
+
|
94 |
+
$available_licenses[ $activations_left . '_' . $premium_license->id ] = $premium_license;
|
95 |
+
}
|
96 |
+
|
97 |
+
$total_available_licenses = count( $available_licenses );
|
98 |
+
if ( $total_available_licenses > 0 ) {
|
99 |
+
$license_input_html = <<< HTML
|
100 |
+
<div class="fs-license-options-container">
|
101 |
+
<table>
|
102 |
+
<tbody>
|
103 |
+
<tr class="fs-available-license-key-container">
|
104 |
+
<td><input type="radio" name="license_type" value="available"></td>
|
105 |
+
<td>
|
106 |
+
HTML;
|
107 |
+
|
108 |
+
if ( $total_available_licenses > 1 ) {
|
109 |
+
// Sort the licenses by number of activations left in descending order.
|
110 |
+
krsort( $available_licenses );
|
111 |
+
|
112 |
+
$license_input_html .= '<select class="fs-licenses">';
|
113 |
+
|
114 |
+
/**
|
115 |
+
* @var FS_Plugin_License $license
|
116 |
+
*/
|
117 |
+
foreach ( $available_licenses as $license ) {
|
118 |
+
$plan = $fs->_get_plan_by_id( $license->plan_id );
|
119 |
+
|
120 |
+
$label = sprintf(
|
121 |
+
"%s-Site %s License - %s",
|
122 |
+
( 1 == $license->quota ?
|
123 |
+
'Single' :
|
124 |
+
( $license->is_unlimited() ? 'Unlimited' : $license->quota )
|
125 |
+
),
|
126 |
+
( is_object( $plan ) ? $plan->title : '' ),
|
127 |
+
$license->get_html_escaped_masked_secret_key()
|
128 |
+
);
|
129 |
+
|
130 |
+
$license_input_html .= "<option data-id='{$license->id}' value='{$license->secret_key}' data-left='{$license->left()}'>{$label}</option>";
|
131 |
+
}
|
132 |
+
|
133 |
+
$license_input_html .= '</select>';
|
134 |
+
} else {
|
135 |
+
$available_licenses = array_values( $available_licenses );
|
136 |
+
|
137 |
+
/**
|
138 |
+
* @var FS_Plugin_License $available_license
|
139 |
+
*/
|
140 |
+
$available_license = $available_licenses[0];
|
141 |
+
$value = sprintf(
|
142 |
+
"%s-Site %s License - %s",
|
143 |
+
( 1 == $available_license->quota ?
|
144 |
+
'Single' :
|
145 |
+
( $available_license->is_unlimited() ? 'Unlimited' : $available_license->quota )
|
146 |
+
),
|
147 |
+
$fs->_get_plan_by_id( $available_license->plan_id )->title,
|
148 |
+
$available_license->get_html_escaped_masked_secret_key()
|
149 |
+
);
|
150 |
+
|
151 |
+
$license_input_html .= <<< HTML
|
152 |
+
<input
|
153 |
+
class="fs-available-license-key"
|
154 |
+
type="text"
|
155 |
+
value="{$value}"
|
156 |
+
data-id="{$available_license->id}"
|
157 |
+
data-license-key="{$available_license->secret_key}"
|
158 |
+
data-left="{$available_license->left()}"
|
159 |
+
readonly />
|
160 |
+
HTML;
|
161 |
+
}
|
162 |
+
|
163 |
+
$license_input_html .= <<< HTML
|
164 |
+
</td>
|
165 |
+
</tr>
|
166 |
+
<tr>
|
167 |
+
<td><input type="radio" name="license_type" value="other"></td>
|
168 |
+
<td class="fs-other-license-key-container">
|
169 |
+
<label for="other_license_key_{$unique_affix}">Other: </label>
|
170 |
+
<div>
|
171 |
+
<input id="other_license_key_{$unique_affix}" class="fs-license-key" type="text" placeholder="Enter license key" tabindex="1">
|
172 |
+
</div>
|
173 |
+
</td>
|
174 |
+
</tr>
|
175 |
+
</tbody>
|
176 |
+
</table>
|
177 |
+
</div>
|
178 |
+
HTML;
|
179 |
+
} else {
|
180 |
+
$license_input_html = "<input class='fs-license-key' type='text' placeholder='{$license_key_text}' tabindex='1' />";
|
181 |
+
}
|
182 |
+
|
183 |
+
$ownership_change_option_text = fs_text_inline( "Associate with the license owner's account.", 'associate-account-with-license-owner', $slug );
|
184 |
+
$ownership_change_option_html = "<div class='ownership-change-option-container' style='display: none'><label><input type='checkbox' /> <strong>{$ownership_change_option_text}</strong></label></div>";
|
185 |
+
|
186 |
+
/**
|
187 |
+
* IMPORTANT:
|
188 |
+
* DO NOT ADD MAXLENGTH OR LIMIT THE LICENSE KEY LENGTH SINCE
|
189 |
+
* WE DO WANT TO ALLOW INPUT OF LONGER KEYS (E.G. WooCommerce Keys)
|
190 |
+
* FOR MIGRATED MODULES.
|
191 |
+
*/
|
192 |
+
$modal_content_html = <<< HTML
|
193 |
+
<div class="notice notice-error inline license-activation-message"><p></p></div>
|
194 |
+
<p>{$message_above_input_field}</p>
|
195 |
+
{$license_input_html}
|
196 |
+
<a class="show-license-resend-modal show-license-resend-modal-{$fs->get_unique_affix()}" href="!#" tabindex="2">{$cant_find_license_key_text}</a>
|
197 |
+
{$network_activation_html}
|
198 |
+
<p>{$message_below_input_field}</p>
|
199 |
+
{$ownership_change_option_html}
|
200 |
+
HTML;
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Handle the ownership change option if not an add-on or if no license yet is activated for the
|
204 |
+
* parent product in case of an add-on.
|
205 |
+
*
|
206 |
+
* @author Leo Fajardo (@leorw)
|
207 |
+
* @since 2.3.2
|
208 |
+
*/
|
209 |
+
$is_user_change_supported = ( ! $fs->is_addon() || ! $fs->get_parent_instance()->has_active_valid_license() );
|
210 |
+
|
211 |
+
fs_enqueue_local_style( 'fs_dialog_boxes', '/admin/dialog-boxes.css' );
|
212 |
+
?>
|
213 |
+
<script type="text/javascript">
|
214 |
+
(function( $ ) {
|
215 |
+
$( document ).ready(function() {
|
216 |
+
var modalContentHtml = <?php echo json_encode($modal_content_html); ?>,
|
217 |
+
modalHtml =
|
218 |
+
'<div class="fs-modal fs-modal-license-activation fs-modal-license-activation-<?php echo $unique_affix ?>">'
|
219 |
+
+ ' <div class="fs-modal-dialog">'
|
220 |
+
+ ' <div class="fs-modal-header">'
|
221 |
+
+ ' <h4><?php echo esc_js($header_title) ?></h4>'
|
222 |
+
+ ' <a href="!#" class="fs-close"><i class="dashicons dashicons-no" title="<?php echo esc_js( fs_text_x_inline( 'Dismiss', 'as close a window', 'dismiss', $slug ) ) ?>"></i></a>'
|
223 |
+
+ ' </div>'
|
224 |
+
+ ' <div class="fs-modal-body">'
|
225 |
+
+ ' <div class="fs-modal-panel active">' + modalContentHtml + '</div>'
|
226 |
+
+ ' </div>'
|
227 |
+
+ ' <div class="fs-modal-footer">'
|
228 |
+
+ ' <button class="button button-secondary button-close" tabindex="4"><?php fs_esc_js_echo_inline( 'Cancel', 'cancel', $slug ) ?></button>'
|
229 |
+
+ ' <button class="button button-primary button-activate-license" tabindex="3"><?php echo esc_js( $activate_button_text ) ?></button>'
|
230 |
+
+ ' </div>'
|
231 |
+
+ ' </div>'
|
232 |
+
+ '</div>',
|
233 |
+
$modal = $(modalHtml),
|
234 |
+
$activateLicenseButton = $modal.find('.button-activate-license'),
|
235 |
+
$licenseKeyInput = $modal.find( 'input.fs-license-key' ),
|
236 |
+
$licenseActivationMessage = $modal.find( '.license-activation-message' ),
|
237 |
+
isNetworkActivation = <?php echo $is_network_activation ? 'true' : 'false' ?>,
|
238 |
+
isUserChangeSupported = <?php echo $is_user_change_supported ? 'true' : 'false' ?>,
|
239 |
+
isSingleSiteActivation = false,
|
240 |
+
$ownershipChangeOptionContainer = $modal.find( '.ownership-change-option-container' ),
|
241 |
+
$body = $( 'body' );
|
242 |
+
|
243 |
+
$modal.appendTo( $body );
|
244 |
+
|
245 |
+
var
|
246 |
+
$licensesDropdown = $modal.find( '.fs-licenses' ),
|
247 |
+
$licenseTypes = $modal.find( 'input[type="radio"][name="license_type"]' ),
|
248 |
+
$applyOnAllSites = $modal.find( '.fs-apply-on-all-sites-checkbox' ),
|
249 |
+
$sitesListContainer = $modal.find( '.fs-sites-list-container' ),
|
250 |
+
$availableLicenseKey = $modal.find( '.fs-available-license-key' ),
|
251 |
+
$otherLicenseKey = $modal.find( '#other_license_key_<?php echo $unique_affix ?>' ),
|
252 |
+
$multisiteOptionsContainer = $modal.find( '.fs-multisite-options-container' ),
|
253 |
+
$activationsLeft = null,
|
254 |
+
hasLicensesDropdown = ( $licensesDropdown.length > 0 ),
|
255 |
+
hasLicenseTypes = ( $licenseTypes.length > 0 ),
|
256 |
+
maxSitesListHeight = null,
|
257 |
+
totalSites = <?php echo count( $sites_details ) ?>,
|
258 |
+
singleBlogID = null;
|
259 |
+
|
260 |
+
var
|
261 |
+
previousLicenseKey = null,
|
262 |
+
otherLicenseOwnerID = null,
|
263 |
+
/**
|
264 |
+
* @author Leo Fajardo (@leorw)
|
265 |
+
* @since 2.3.2
|
266 |
+
*/
|
267 |
+
resetLoadingMode = function () {
|
268 |
+
// Reset loading mode.
|
269 |
+
$activateLicenseButton.text( <?php echo json_encode( $activate_button_text ) ?> );
|
270 |
+
$activateLicenseButton.prop( 'disabled', false );
|
271 |
+
$( document.body ).css( { 'cursor': 'auto' } );
|
272 |
+
$( '.fs-loading' ).removeClass( 'fs-loading' );
|
273 |
+
|
274 |
+
console.log( 'resetLoadingMode - Primary button was enabled' );
|
275 |
+
},
|
276 |
+
/**
|
277 |
+
* @author Leo Fajardo (@leorw)
|
278 |
+
* @since 2.3.2
|
279 |
+
*/
|
280 |
+
setLoadingMode = function () {
|
281 |
+
$( document.body ).css( { 'cursor': 'wait' } );
|
282 |
+
},
|
283 |
+
/**
|
284 |
+
* @author Leo Fajardo (@leorw)
|
285 |
+
* @since 2.3.2
|
286 |
+
*/
|
287 |
+
afterLicenseUserDataLoaded = function () {
|
288 |
+
if (
|
289 |
+
null !== otherLicenseOwnerID &&
|
290 |
+
otherLicenseOwnerID != <?php echo $fs->is_registered() ? $fs->get_user()->id : 'null' ?>
|
291 |
+
) {
|
292 |
+
$ownershipChangeOptionContainer.show();
|
293 |
+
} else {
|
294 |
+
$ownershipChangeOptionContainer.hide();
|
295 |
+
$activateLicenseButton.focus();
|
296 |
+
}
|
297 |
+
},
|
298 |
+
/**
|
299 |
+
* @author Leo Fajardo (@leorw)
|
300 |
+
* @since 2.3.2
|
301 |
+
*/
|
302 |
+
fetchLicenseUserData = function () {
|
303 |
+
var hideAndUncheckUserChangeCheckbox = ( ! isUserChangeSupported ),
|
304 |
+
otherLicenseKeyIsSelected = isOtherLicenseKeySelected();
|
305 |
+
|
306 |
+
if ( ! hideAndUncheckUserChangeCheckbox ) {
|
307 |
+
// User change is supported only on the site level.
|
308 |
+
hideAndUncheckUserChangeCheckbox = ( isNetworkActivation || isSingleSiteActivation );
|
309 |
+
}
|
310 |
+
|
311 |
+
if ( ! hideAndUncheckUserChangeCheckbox ) {
|
312 |
+
hideAndUncheckUserChangeCheckbox = ( hasLicenseTypes && ! otherLicenseKeyIsSelected );
|
313 |
+
}
|
314 |
+
|
315 |
+
var licenseKey = $licenseKeyInput.val().trim();
|
316 |
+
|
317 |
+
if ( ! hideAndUncheckUserChangeCheckbox && otherLicenseKeyIsSelected ) {
|
318 |
+
hideAndUncheckUserChangeCheckbox = ( licenseKey.length < 32 );
|
319 |
+
}
|
320 |
+
|
321 |
+
if ( licenseKey !== previousLicenseKey ) {
|
322 |
+
// If the license key has not been changed, keep the owner ID in order to prevent another API call.
|
323 |
+
otherLicenseOwnerID = null;
|
324 |
+
}
|
325 |
+
|
326 |
+
if ( hideAndUncheckUserChangeCheckbox ) {
|
327 |
+
$ownershipChangeOptionContainer.hide().find( 'input' ).attr( 'checked', false );
|
328 |
+
|
329 |
+
return;
|
330 |
+
}
|
331 |
+
|
332 |
+
if ( null !== otherLicenseOwnerID ) {
|
333 |
+
afterLicenseUserDataLoaded();
|
334 |
+
return;
|
335 |
+
}
|
336 |
+
|
337 |
+
setLoadingMode();
|
338 |
+
|
339 |
+
$activateLicenseButton.addClass( 'fs-loading' );
|
340 |
+
$activateLicenseButton.attr( 'disabled', 'disabled' );
|
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' ) ?>',
|
348 |
+
security : '<?php echo $fs->get_ajax_security( 'fetch_is_marketing_required_flag_value' ) ?>',
|
349 |
+
license_key: licenseKey,
|
350 |
+
module_id : '<?php echo $fs->get_id() ?>'
|
351 |
+
},
|
352 |
+
success: function ( result ) {
|
353 |
+
resetLoadingMode();
|
354 |
+
|
355 |
+
if ( result.success ) {
|
356 |
+
result = result.data;
|
357 |
+
|
358 |
+
// Cache license owner's ID.
|
359 |
+
otherLicenseOwnerID = result.license_owner_id;
|
360 |
+
}
|
361 |
+
|
362 |
+
afterLicenseUserDataLoaded();
|
363 |
+
}
|
364 |
+
} );
|
365 |
+
};
|
366 |
+
|
367 |
+
function registerEventHandlers() {
|
368 |
+
var
|
369 |
+
$otherLicenseKeyContainer = $modal.find( '.fs-other-license-key-container' );
|
370 |
+
|
371 |
+
if ( isNetworkActivation ) {
|
372 |
+
$applyOnAllSites.click(function() {
|
373 |
+
var applyOnAllSites = $( this ).is( ':checked' );
|
374 |
+
|
375 |
+
$multisiteOptionsContainer.toggleClass( 'fs-apply-on-all-sites', applyOnAllSites );
|
376 |
+
|
377 |
+
showSites( ! applyOnAllSites );
|
378 |
+
|
379 |
+
if ( hasValidLicenseKey() && ( applyOnAllSites || hasSelectedSite() ) ) {
|
380 |
+
enableActivateLicenseButton();
|
381 |
+
} else {
|
382 |
+
disableActivateLicenseButton();
|
383 |
+
}
|
384 |
+
});
|
385 |
+
|
386 |
+
$sitesListContainer.delegate( 'td:not(:first-child)', 'click', function() {
|
387 |
+
// If a site row is clicked, trigger a click on the checkbox.
|
388 |
+
$( this ).parent().find( 'td:first-child input' ).click();
|
389 |
+
});
|
390 |
+
|
391 |
+
$sitesListContainer.delegate( 'input[type="checkbox"]', 'click', function() {
|
392 |
+
enableDisableSitesSelection();
|
393 |
+
|
394 |
+
if ( hasValidLicenseKey() && hasSelectedSite() ) {
|
395 |
+
enableActivateLicenseButton();
|
396 |
+
} else {
|
397 |
+
disableActivateLicenseButton();
|
398 |
+
}
|
399 |
+
});
|
400 |
+
}
|
401 |
+
|
402 |
+
if ( hasLicensesDropdown ) {
|
403 |
+
$licensesDropdown.change(function() {
|
404 |
+
// When a license is selected, select the associated radio button.
|
405 |
+
$licenseTypes.filter( '[value="available"]' ).attr( 'checked', true );
|
406 |
+
|
407 |
+
if ( ! isNetworkActivation || $modal.hasClass( 'is-single-site-activation' ) ) {
|
408 |
+
enableActivateLicenseButton();
|
409 |
+
return true;
|
410 |
+
}
|
411 |
+
|
412 |
+
toggleActivationOnAllSites();
|
413 |
+
})
|
414 |
+
}
|
415 |
+
|
416 |
+
if ( hasLicenseTypes ) {
|
417 |
+
$licenseTypes.change(function() {
|
418 |
+
var
|
419 |
+
licenseKey = $modal.find( 'input.fs-license-key' ).val().trim(),
|
420 |
+
otherLicenseKeySelected = isOtherLicenseKeySelected();
|
421 |
+
|
422 |
+
if ( ( licenseKey.length > 0 || ( hasLicenseTypes && ! otherLicenseKeySelected ) ) &&
|
423 |
+
( $modal.hasClass( 'is-single-site-activation' ) || ! isNetworkActivation || hasSelectedSite() )
|
424 |
+
) {
|
425 |
+
/**
|
426 |
+
* If the "other" license is not empty or an available license is selected, enable the activate
|
427 |
+
* button.
|
428 |
+
*
|
429 |
+
* @author Leo Fajardo (@leorw)
|
430 |
+
*/
|
431 |
+
enableActivateLicenseButton();
|
432 |
+
} else {
|
433 |
+
disableActivateLicenseButton();
|
434 |
+
}
|
435 |
+
|
436 |
+
if ( '' !== licenseKey ) {
|
437 |
+
fetchLicenseUserData();
|
438 |
+
}
|
439 |
+
|
440 |
+
if ( ! isNetworkActivation ) {
|
441 |
+
return;
|
442 |
+
}
|
443 |
+
|
444 |
+
if ( otherLicenseKeySelected ) {
|
445 |
+
$applyOnAllSites.attr( 'disabled', false );
|
446 |
+
enableDisableSitesSelection();
|
447 |
+
resetActivateLicenseCheckboxLabel();
|
448 |
+
} else if ( ! $modal.hasClass( 'is-single-site-activation' ) ) {
|
449 |
+
toggleActivationOnAllSites();
|
450 |
+
}
|
451 |
+
});
|
452 |
+
|
453 |
+
if ( ! hasLicensesDropdown ) {
|
454 |
+
$availableLicenseKey.click(function() {
|
455 |
+
$licenseTypes.filter( '[value="available"]' ).click();
|
456 |
+
});
|
457 |
+
}
|
458 |
+
|
459 |
+
$otherLicenseKeyContainer.click(function() {
|
460 |
+
$licenseTypes.filter( '[value="other"]' ).click();
|
461 |
+
});
|
462 |
+
}
|
463 |
+
|
464 |
+
$body.on( 'click', 'span.activate-license.<?php echo $unique_affix ?> a, .activate-license-trigger.<?php echo $unique_affix ?>', function (evt) {
|
465 |
+
evt.preventDefault();
|
466 |
+
|
467 |
+
showModal( evt );
|
468 |
+
});
|
469 |
+
|
470 |
+
var licenseTimeout = null;
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Disable activation button when license key is empty.
|
474 |
+
*
|
475 |
+
* @author Leo Fajardo (@leorw)
|
476 |
+
* @since 2.3.2
|
477 |
+
*/
|
478 |
+
$modal.on( 'keyup paste delete cut', 'input.fs-license-key', function () {
|
479 |
+
clearTimeout(licenseTimeout);
|
480 |
+
|
481 |
+
licenseTimeout = setTimeout( function () {
|
482 |
+
var licenseKey = $licenseKeyInput.val().trim();
|
483 |
+
|
484 |
+
if ( licenseKey == previousLicenseKey ) {
|
485 |
+
afterLicenseUserDataLoaded();
|
486 |
+
return;
|
487 |
+
}
|
488 |
+
|
489 |
+
if ( '' === licenseKey ) {
|
490 |
+
disableActivateLicenseButton();
|
491 |
+
$ownershipChangeOptionContainer.hide();
|
492 |
+
} else {
|
493 |
+
enableActivateLicenseButton();
|
494 |
+
|
495 |
+
if ( 32 <= licenseKey.length ) {
|
496 |
+
fetchLicenseUserData();
|
497 |
+
} else {
|
498 |
+
$ownershipChangeOptionContainer.hide();
|
499 |
+
}
|
500 |
+
}
|
501 |
+
|
502 |
+
previousLicenseKey = licenseKey;
|
503 |
+
}, 200 );
|
504 |
+
} ).focus();
|
505 |
+
|
506 |
+
$modal.on('input propertychange', 'input.fs-license-key', function () {
|
507 |
+
|
508 |
+
var licenseKey = $(this).val().trim();
|
509 |
+
|
510 |
+
/**
|
511 |
+
* If license key is not empty, enable the license activation button.
|
512 |
+
*/
|
513 |
+
if ( licenseKey.length > 0 && ( $modal.hasClass( 'is-single-site-activation' ) || ! isNetworkActivation || hasSelectedSite() ) ) {
|
514 |
+
enableActivateLicenseButton();
|
515 |
+
}
|
516 |
+
});
|
517 |
+
|
518 |
+
$modal.on( 'blur', 'input.fs-license-key', function( evt ) {
|
519 |
+
var
|
520 |
+
licenseKey = $(this).val().trim(),
|
521 |
+
$focusedElement = $( evt.relatedTarget ),
|
522 |
+
hasSelectedAvailableLicense = ( hasLicenseTypes && $focusedElement.parents( '.fs-available-license-key-container' ).length > 0 );
|
523 |
+
|
524 |
+
/**
|
525 |
+
* If license key is empty, disable the license activation button.
|
526 |
+
*/
|
527 |
+
if ( ( 0 === licenseKey.length && ( ! hasLicenseTypes || ! hasSelectedAvailableLicense ) ) ||
|
528 |
+
( isNetworkActivation && ! hasSelectedSite() )
|
529 |
+
) {
|
530 |
+
disableActivateLicenseButton();
|
531 |
+
}
|
532 |
+
});
|
533 |
+
|
534 |
+
$modal.on('click', '.button-activate-license', function (evt) {
|
535 |
+
evt.preventDefault();
|
536 |
+
|
537 |
+
if ($(this).hasClass('disabled')) {
|
538 |
+
return;
|
539 |
+
}
|
540 |
+
|
541 |
+
var
|
542 |
+
licenseKey = '';
|
543 |
+
|
544 |
+
if ( hasLicenseTypes ) {
|
545 |
+
if ( isOtherLicenseKeySelected() ) {
|
546 |
+
licenseKey = $otherLicenseKey.val();
|
547 |
+
} else {
|
548 |
+
if ( ! hasLicensesDropdown ) {
|
549 |
+
licenseKey = $availableLicenseKey.data( 'license-key' );
|
550 |
+
} else {
|
551 |
+
licenseKey = $licensesDropdown.val();
|
552 |
+
}
|
553 |
+
}
|
554 |
+
} else {
|
555 |
+
licenseKey = $licenseKeyInput.val().trim();
|
556 |
+
}
|
557 |
+
|
558 |
+
disableActivateLicenseButton();
|
559 |
+
|
560 |
+
if (0 === licenseKey.length) {
|
561 |
+
return;
|
562 |
+
}
|
563 |
+
|
564 |
+
var data = {
|
565 |
+
action : '<?php echo $fs->get_ajax_action( 'activate_license' ) ?>',
|
566 |
+
security : '<?php echo $fs->get_ajax_security( 'activate_license' ) ?>',
|
567 |
+
license_key: licenseKey,
|
568 |
+
module_id : '<?php echo $fs->get_id() ?>'
|
569 |
+
};
|
570 |
+
|
571 |
+
if ( isNetworkActivation ) {
|
572 |
+
var
|
573 |
+
sites = [];
|
574 |
+
|
575 |
+
if ( null === singleBlogID ) {
|
576 |
+
var
|
577 |
+
applyOnAllSites = $applyOnAllSites.is( ':checked' );
|
578 |
+
|
579 |
+
$sitesListContainer.find( 'tr' ).each(function() {
|
580 |
+
var
|
581 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|