PluginProbe
Polylang / 3.8.8
Polylang v3.8.8
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 / src / license.php

license.php in Polylang 3.8.8, at src/license.php

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