PluginProbe
Polylang / 3.7.2
Polylang v3.7.2
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / include / license.php

license.php in Polylang 3.7.2, at include/license.php

356 lines 9.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * A class to easily manage licenses for Polylang Pro and addons
8 *
9 * @since 1.9
10 */
11 class PLL_License {
12 /**
13 * Sanitized plugin name.
14 *
15 * @var string
16 */
17 public $id;
18
19 /**
20 * Plugin name.
21 *
22 * @var string
23 */
24 public $name;
25
26 /**
27 * License key.
28 *
29 * @var string
30 */
31 public $license_key;
32
33 /**
34 * License data, obtained from the API request.
35 *
36 * @var stdClass|null
37 */
38 public $license_data;
39
40 /**
41 * Main plugin file.
42 *
43 * @var string
44 */
45 private $file;
46
47 /**
48 * Current plugin version.
49 *
50 * @var string
51 */
52 private $version;
53
54 /**
55 * Plugin author.
56 *
57 * @var string
58 */
59 private $author;
60
61 /**
62 * API url.
63 *
64 * @var string.
65 */
66 private $api_url = 'https://polylang.pro';
67
68 /**
69 * Constructor
70 *
71 * @since 1.9
72 *
73 * @param string $file The plugin file.
74 * @param string $item_name The plugin name.
75 * @param string $version The plugin version.
76 * @param string $author Author name.
77 * @param string $api_url Optional url of the site managing the license.
78 */
79 public function __construct( $file, $item_name, $version, $author, $api_url = null ) {
80 $this->id = sanitize_title( $item_name );
81 $this->file = $file;
82 $this->name = $item_name;
83 $this->version = $version;
84 $this->author = $author;
85 $this->api_url = empty( $api_url ) ? $this->api_url : $api_url;
86
87 $licenses = (array) get_option( 'polylang_licenses', array() );
88 $license = isset( $licenses[ $this->id ] ) && is_array( $licenses[ $this->id ] ) ? $licenses[ $this->id ] : array();
89 $this->license_key = ! empty( $license['key'] ) ? (string) $license['key'] : '';
90
91 if ( ! empty( $license['data'] ) ) {
92 $this->license_data = (object) $license['data'];
93 }
94
95 // Updater
96 $this->auto_updater();
97
98 // Register settings
99 add_filter( 'pll_settings_licenses', array( $this, 'settings' ) );
100
101 // Weekly schedule
102 if ( ! wp_next_scheduled( 'polylang_check_licenses' ) ) {
103 wp_schedule_event( time(), 'weekly', 'polylang_check_licenses' );
104 }
105
106 add_action( 'polylang_check_licenses', array( $this, 'check_license' ) );
107 }
108
109 /**
110 * Auto updater
111 *
112 * @since 1.9
113 *
114 * @return void
115 */
116 public function auto_updater() {
117 $args = array(
118 'version' => $this->version,
119 'license' => $this->license_key,
120 'author' => $this->author,
121 'item_name' => $this->name,
122 );
123
124 // Setup the updater
125 new PLL_Plugin_Updater( $this->api_url, $this->file, $args );
126 }
127
128 /**
129 * Registers the licence in the Settings.
130 *
131 * @since 1.9
132 *
133 * @param PLL_License[] $items Array of objects allowing to manage a license.
134 * @return PLL_License[]
135 */
136 public function settings( $items ) {
137 $items[ $this->id ] = $this;
138 return $items;
139 }
140
141 /**
142 * Activates the license key.
143 *
144 * @since 1.9
145 *
146 * @param string $license_key Activation key.
147 * @return PLL_License Updated PLL_License object.
148 */
149 public function activate_license( $license_key ) {
150 $this->license_key = $license_key;
151 $this->api_request( 'activate_license' );
152
153 // Tell WordPress to look for updates.
154 delete_site_transient( 'update_plugins' );
155 return $this;
156 }
157
158
159 /**
160 * Deactivates the license key.
161 *
162 * @since 1.9
163 *
164 * @return PLL_License Updated PLL_License object.
165 */
166 public function deactivate_license() {
167 $this->api_request( 'deactivate_license' );
168 return $this;
169 }
170
171 /**
172 * Checks if the license key is valid.
173 *
174 * @since 1.9
175 *
176 * @return void
177 */
178 public function check_license() {
179 $this->api_request( 'check_license' );
180 }
181
182 /**
183 * Sends an api request to check, activate or deactivate the license
184 * Updates the licenses option according to the status
185 *
186 * @since 1.9
187 *
188 * @param string $request check_license | activate_license | deactivate_license
189 * @return void
190 */
191 private function api_request( $request ) {
192 $licenses = get_option( 'polylang_licenses' );
193
194 if ( is_array( $licenses ) ) {
195 unset( $licenses[ $this->id ] );
196 } else {
197 $licenses = array();
198 }
199 unset( $this->license_data );
200
201 if ( ! empty( $this->license_key ) ) {
202 // Data to send in our API request
203 $api_params = array(
204 'edd_action' => $request,
205 'license' => $this->license_key,
206 'item_name' => urlencode( $this->name ),
207 'url' => home_url(),
208 );
209
210 // Call the API
211 $response = wp_remote_post(
212 $this->api_url,
213 array(
214 'timeout' => 3,
215 'sslverify' => false,
216 'body' => $api_params,
217 )
218 );
219
220 // Update the option only if we got a response
221 if ( is_wp_error( $response ) ) {
222 return;
223 }
224
225 // Save new license info
226 $licenses[ $this->id ] = array( 'key' => $this->license_key );
227 $data = (object) json_decode( wp_remote_retrieve_body( $response ) );
228
229 if ( isset( $data->license ) && 'deactivated' !== $data->license ) {
230 $licenses[ $this->id ]['data'] = $this->license_data = $data;
231 }
232 }
233
234 update_option( 'polylang_licenses', $licenses ); // FIXME called multiple times when saving all licenses
235 }
236
237 /**
238 * Get the html form field in a table row (one per license key) for display
239 *
240 * @since 2.7
241 *
242 * @return string
243 */
244 public function get_form_field() {
245 if ( ! empty( $this->license_data ) ) {
246 $license = $this->license_data;
247 }
248
249 $class = 'license-null';
250 $message = '';
251
252 $out = sprintf(
253 '<td><label for="pll-licenses[%1$s]">%2$s</label></td>' .
254 '<td><input name="licenses[%1$s]" id="pll-licenses[%1$s]" type="password" value="%3$s" class="regular-text code" />',
255 esc_attr( $this->id ),
256 esc_attr( $this->name ),
257 esc_html( $this->license_key )
258 );
259
260 if ( ! empty( $license ) && is_object( $license ) ) {
261 $now = time();
262 $expiration = isset( $license->expires ) ? strtotime( $license->expires ) : false;
263
264 // Special case: the license expired after the last check
265 if ( $license->success && $expiration && $expiration < $now ) {
266 $license->success = false;
267 $license->error = 'expired';
268 }
269
270 if ( false === $license->success ) {
271 $class = 'notice-error notice-alt';
272
273 switch ( $license->error ) {
274 case 'expired':
275 $message = sprintf(
276 /* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
277 esc_html__( 'Your license key expired on %1$s. Please %2$srenew your license key%3$s.', 'polylang' ),
278 esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
279 sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account/' ),
280 '</a>'
281 );
282 break;
283
284 case 'disabled':
285 case 'revoked':
286 $message = esc_html__( 'Your license key has been disabled.', 'polylang' );
287 break;
288
289 case 'missing':
290 $message = sprintf(
291 /* translators: %1$s is link start tag, %2$s is link end tag. */
292 esc_html__( 'Invalid license. Please %1$svisit your account page%2$s and verify it.', 'polylang' ),
293 sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account/' ),
294 '</a>'
295 );
296 break;
297
298 case 'invalid':
299 case 'site_inactive':
300 $message = sprintf(
301 /* translators: %1$s is a product name, %2$s is link start tag, %3$s is link end tag. */
302 esc_html__( 'Your %1$s license key is not active for this URL. Please %2$svisit your account page%3$s to manage your license key URLs.', 'polylang' ),
303 esc_html( $this->name ),
304 sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account/' ),
305 '</a>'
306 );
307 break;
308
309 case 'item_name_mismatch':
310 /* translators: %s is a product name */
311 $message = sprintf( esc_html__( 'This is not a %s license key.', 'polylang' ), esc_html( $this->name ) );
312 break;
313
314 case 'no_activations_left':
315 $message = sprintf(
316 /* translators: %1$s is link start tag, %2$s is link end tag */
317 esc_html__( 'Your license key has reached its activation limit. %1$sView possible upgrades%2$s now.', 'polylang' ),
318 sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account/' ),
319 '</a>'
320 );
321 break;
322 }
323 } else {
324 $class = 'license-valid';
325
326 $out .= sprintf( '<button id="deactivate_%s" type="button" class="button button-secondary pll-deactivate-license">%s</button>', esc_attr( $this->id ), esc_html__( 'Deactivate', 'polylang' ) );
327
328 if ( 'lifetime' === $license->expires ) {
329 $message = esc_html__( 'The license key never expires.', 'polylang' );
330 } elseif ( $expiration > $now && $expiration - $now < ( DAY_IN_SECONDS * 30 ) ) {
331 $class = 'notice-warning notice-alt';
332 $message = sprintf(
333 /* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
334 esc_html__( 'Your license key will expire soon! Precisely, it will expire on %1$s. %2$sRenew your license key today!%3$s', 'polylang' ),
335 esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
336 sprintf( '<a href="%s" target="_blank">', 'https://polylang.pro/account/' ),
337 '</a>'
338 );
339 } else {
340 $message = sprintf(
341 /* translators: %s is a date */
342 esc_html__( 'Your license key expires on %s.', 'polylang' ),
343 esc_html( date_i18n( get_option( 'date_format' ), $expiration ) )
344 );
345 }
346 }
347 }
348
349 if ( ! empty( $message ) ) {
350 $out .= '<p>' . $message . '</p>';
351 }
352
353 return sprintf( '<tr id="pll-license-%s" class="%s">%s</tr>', esc_attr( $this->id ), $class, $out );
354 }
355 }
356