PluginProbe
Polylang / 3.7.7
Polylang v3.7.7
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.7, at include/license.php

363 lines 9.3 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( $license_key ) {
157 $this->license_key = $license_key;
158 $this->api_request( 'activate_license' );
159
160 // Tell WordPress to look for updates.
161 delete_site_transient( 'update_plugins' );
162 return $this;
163 }
164
165
166 /**
167 * Deactivates the license key.
168 *
169 * @since 1.9
170 *
171 * @return PLL_License Updated PLL_License object.
172 */
173 public function deactivate_license() {
174 $this->api_request( 'deactivate_license' );
175 return $this;
176 }
177
178 /**
179 * Checks if the license key is valid.
180 *
181 * @since 1.9
182 *
183 * @return void
184 */
185 public function check_license() {
186 $this->api_request( 'check_license' );
187 }
188
189 /**
190 * Sends an api request to check, activate or deactivate the license
191 * Updates the licenses option according to the status
192 *
193 * @since 1.9
194 *
195 * @param string $request check_license | activate_license | deactivate_license
196 * @return void
197 */
198 private function api_request( $request ) {
199 $licenses = get_option( 'polylang_licenses' );
200
201 if ( is_array( $licenses ) ) {
202 unset( $licenses[ $this->id ] );
203 } else {
204 $licenses = array();
205 }
206 unset( $this->license_data );
207
208 if ( ! empty( $this->license_key ) ) {
209 // Data to send in our API request
210 $api_params = array(
211 'edd_action' => $request,
212 'license' => $this->license_key,
213 'item_name' => urlencode( $this->name ),
214 'url' => home_url(),
215 );
216
217 // Call the API
218 $response = wp_remote_post(
219 $this->api_url,
220 array(
221 'timeout' => 3,
222 'sslverify' => false,
223 'body' => $api_params,
224 )
225 );
226
227 // Update the option only if we got a response
228 if ( is_wp_error( $response ) ) {
229 return;
230 }
231
232 // Save new license info
233 $licenses[ $this->id ] = array( 'key' => $this->license_key );
234 $data = (object) json_decode( wp_remote_retrieve_body( $response ) );
235
236 if ( isset( $data->license ) && 'deactivated' !== $data->license ) {
237 $licenses[ $this->id ]['data'] = $this->license_data = $data;
238 }
239 }
240
241 update_option( 'polylang_licenses', $licenses ); // FIXME called multiple times when saving all licenses
242 }
243
244 /**
245 * Get the html form field in a table row (one per license key) for display
246 *
247 * @since 2.7
248 *
249 * @return string
250 */
251 public function get_form_field() {
252 if ( ! empty( $this->license_data ) ) {
253 $license = $this->license_data;
254 }
255
256 $class = 'license-null';
257 $message = '';
258
259 $out = sprintf(
260 '<td><label for="pll-licenses[%1$s]">%2$s</label></td>' .
261 '<td><input name="licenses[%1$s]" id="pll-licenses[%1$s]" type="password" value="%3$s" class="regular-text code" />',
262 esc_attr( $this->id ),
263 esc_attr( $this->name ),
264 esc_html( $this->license_key )
265 );
266
267 if ( ! empty( $license ) && is_object( $license ) ) {
268 $now = time();
269 $expiration = isset( $license->expires ) ? strtotime( $license->expires ) : false;
270
271 // Special case: the license expired after the last check
272 if ( $license->success && $expiration && $expiration < $now ) {
273 $license->success = false;
274 $license->error = 'expired';
275 }
276
277 if ( false === $license->success ) {
278 $class = 'notice-error notice-alt';
279
280 switch ( $license->error ) {
281 case 'expired':
282 $message = sprintf(
283 /* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
284 esc_html__( 'Your license key expired on %1$s. Please %2$srenew your license key%3$s.', 'polylang' ),
285 esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
286 sprintf( '<a href="%s" target="_blank">', self::ACCOUNT_URL ),
287 '</a>'
288 );
289 break;
290
291 case 'disabled':
292 case 'revoked':
293 $message = esc_html__( 'Your license key has been disabled.', 'polylang' );
294 break;
295
296 case 'missing':
297 $message = sprintf(
298 /* translators: %1$s is link start tag, %2$s is link end tag. */
299 esc_html__( 'Invalid license. Please %1$svisit your account page%2$s and verify it.', 'polylang' ),
300 sprintf( '<a href="%s" target="_blank">', self::ACCOUNT_URL ),
301 '</a>'
302 );
303 break;
304
305 case 'invalid':
306 case 'site_inactive':
307 $message = sprintf(
308 /* translators: %1$s is a product name, %2$s is link start tag, %3$s is link end tag. */
309 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' ),
310 esc_html( $this->name ),
311 sprintf( '<a href="%s" target="_blank">', self::ACCOUNT_URL ),
312 '</a>'
313 );
314 break;
315
316 case 'item_name_mismatch':
317 /* translators: %s is a product name */
318 $message = sprintf( esc_html__( 'This is not a %s license key.', 'polylang' ), esc_html( $this->name ) );
319 break;
320
321 case 'no_activations_left':
322 $message = sprintf(
323 /* translators: %1$s is link start tag, %2$s is link end tag */
324 esc_html__( 'Your license key has reached its activation limit. %1$sView possible upgrades%2$s now.', 'polylang' ),
325 sprintf( '<a href="%s" target="_blank">', self::ACCOUNT_URL ),
326 '</a>'
327 );
328 break;
329 }
330 } else {
331 $class = 'license-valid';
332
333 $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' ) );
334
335 if ( 'lifetime' === $license->expires ) {
336 $message = esc_html__( 'The license key never expires.', 'polylang' );
337 } elseif ( $expiration > $now && $expiration - $now < ( DAY_IN_SECONDS * 30 ) ) {
338 $class = 'notice-warning notice-alt';
339 $message = sprintf(
340 /* translators: %1$s is a date, %2$s is link start tag, %3$s is link end tag. */
341 esc_html__( 'Your license key will expire soon! Precisely, it will expire on %1$s. %2$sRenew your license key today!%3$s', 'polylang' ),
342 esc_html( date_i18n( get_option( 'date_format' ), $expiration ) ),
343 sprintf( '<a href="%s" target="_blank">', self::ACCOUNT_URL ),
344 '</a>'
345 );
346 } else {
347 $message = sprintf(
348 /* translators: %s is a date */
349 esc_html__( 'Your license key expires on %s.', 'polylang' ),
350 esc_html( date_i18n( get_option( 'date_format' ), $expiration ) )
351 );
352 }
353 }
354 }
355
356 if ( ! empty( $message ) ) {
357 $out .= '<p>' . $message . '</p>';
358 }
359
360 return sprintf( '<tr id="pll-license-%s" class="%s">%s</tr>', esc_attr( $this->id ), $class, $out );
361 }
362 }
363