PluginProbe
wpForo Forum / 3.2.2
wpForo Forum v3.2.2
3.2.2 3.2.1 3.2.0 3.1.7 3.1.6 3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 All 142 releases
← All changes | admin/pages/license/src/Services/LicenseService.php +78 -9 3.1.5 → 3.2.2 View file →
@@ -220,12 +220,14 @@
220 220
221 221 // Process every license result — update local storage and notices
222 222 foreach( $key_to_product as $license_key => $product_id ) {
223 223 if( ! isset( $batch_results[ $license_key ] ) ) continue;
224 -
225 - $result = $batch_results[ $license_key ];
226 - $license = $licenses[ $product_id ];
227 -
224 +
225 + $result = $batch_results[ $license_key ];
226 + $license = $licenses[ $product_id ];
227 + $product_id = $this->sync_product_key( $product_id, $result );
228 + if( $product_id === '' ) continue;
229 +
228 230 if( ! empty( $result['success'] ) && ! empty( $result['data'] ) ) {
229 231 $this->save( $product_id, $result['data'] );
230 232
231 233 // Clear any expired notice for this license
@@ -302,9 +304,11 @@
302 304 $is_terminal = in_array( $server_reason, self::REFUND_REASONS, true )
303 305 || in_array( $server_status, self::TERMINAL_STATUSES, true )
304 306 || $server_reason === 'not_found';
305 307
306 - if( $is_terminal ) {
308 + if( $is_terminal && self::is_legacy_license( $license ) ) {
309 + $this->keep_legacy_license( $product_id, $license );
310 + } elseif( $is_terminal ) {
307 311 $plugin_slug = $license['plugin_slug'] ?? '';
308 312 $this->remove( $product_id );
309 313
310 314 if( $plugin_slug ) {
@@ -346,8 +350,51 @@
346 350 }
347 351 }
348 352
349 353 /**
354 + * A license migrated from the old gVectors store (legacy activation key).
355 + */
356 + private static function is_legacy_license( array $license ): bool {
357 + return ( $license['plan_name'] ?? '' ) === 'Legacy License';
358 + }
359 +
360 + /**
361 + * A legacy license the server no longer knows or reports invalid: old-store owners keep using their
362 + * addon for life, so the license is kept as expired (no updates) and the addon is never deactivated or deleted.
363 + */
364 + private function keep_legacy_license( string $product_id, array $license ): void {
365 + $license['status'] = 'expired';
366 + $license['last_validated'] = time();
367 + $this->save( $product_id, $license );
368 + $this->update_expired_notice( $product_id );
369 + }
370 +
371 + /**
372 + * If the server reports a real Paddle product_id different from the local key
373 + * (e.g. a migrated legacy license stored under its plugin slug), move the local
374 + * license to that key so the store UI treats it like any purchased license.
375 + * Returns the key to continue with, or '' when the entry was dropped because an
376 + * active license already exists under the server's product_id.
377 + */
378 + private function sync_product_key( string $product_id, array $result ): string {
379 + $server_pid = $result['data']['product_id'] ?? '';
380 + if( ! is_string( $server_pid ) || strpos( $server_pid, 'pro_' ) !== 0 || $server_pid === $product_id ) return $product_id;
381 +
382 + $licenses = $this->get_all();
383 + if( ! isset( $licenses[ $product_id ] ) ) return $product_id;
384 +
385 + $keep_existing = isset( $licenses[ $server_pid ] ) && $this->is_active( $server_pid );
386 + if( ! $keep_existing ) {
387 + $licenses[ $server_pid ] = $licenses[ $product_id ];
388 + $licenses[ $server_pid ]['product_id'] = $server_pid;
389 + }
390 + unset( $licenses[ $product_id ] );
391 + update_option( $this->option_key, $licenses );
392 +
393 + return $keep_existing ? '' : $server_pid;
394 + }
395 +
396 + /**
350 397 * Remove a license for a product
351 398 */
352 399 public function remove( string $product_id ): bool {
353 400 $licenses = $this->get_all();
@@ -405,9 +452,11 @@
405 452 if( empty( $license ) ) return;
406 453
407 454 $plugin_slug = $license['plugin_slug'] ?? '';
408 455 if( empty( $plugin_slug ) ) return;
409 -
456 + // Addon not physically installed — no notice needed
457 + if( ! is_dir( WP_PLUGIN_DIR . '/' . $plugin_slug ) ) return;
458 +
410 459 $expired_notices = get_option( $this->expired_notice_option, [] );
411 460 $expired_notices[ $plugin_slug ] = [
412 461 'product_name' => $license['product_name'] ?? $plugin_slug,
413 462 'status' => $license['status'] ?? 'expired',
@@ -465,8 +514,13 @@
465 514 'addon_deleted' => false,
466 515 ];
467 516 }
468 517
518 + $product_id = $this->sync_product_key( $product_id, $response );
519 + if( $product_id === '' ) {
520 + return [ 'valid' => false, 'reason' => 'duplicate', 'error' => '', 'status' => '', 'removed' => true, 'addon_deleted' => false ];
521 + }
522 +
469 523 // License is valid on the server
470 524 if( ! empty( $response['success'] ) && ! empty( $response['data'] ) ) {
471 525 $this->save( $product_id, $response['data'] );
472 526
@@ -508,8 +562,21 @@
508 562 $is_terminal = in_array( $server_reason, self::REFUND_REASONS, true )
509 563 || in_array( $server_status, self::TERMINAL_STATUSES, true )
510 564 || $server_reason === 'not_found';
511 565
566 + if( $is_terminal && self::is_legacy_license( $license ) ) {
567 + $this->keep_legacy_license( $product_id, $license );
568 +
569 + return [
570 + 'valid' => false,
571 + 'reason' => $server_reason ?: $server_status,
572 + 'error' => $server_error,
573 + 'status' => 'expired',
574 + 'removed' => false,
575 + 'addon_deleted' => false,
576 + ];
577 + }
578 +
512 579 $removed = false;
513 580 $addon_deleted = false;
514 581
515 582 if( $is_terminal ) {
@@ -616,11 +683,13 @@
616 683
617 684 foreach( $keys_to_validate as $license_key => $product_id ) {
618 685 if( ! isset( $batch_results[ $license_key ] ) ) continue;
619 686
620 - $result = $batch_results[ $license_key ];
621 - $license = $licenses[ $product_id ];
622 -
687 + $result = $batch_results[ $license_key ];
688 + $license = $licenses[ $product_id ];
689 + $product_id = $this->sync_product_key( $product_id, $result );
690 + if( $product_id === '' ) continue;
691 +
623 692 if( ! empty( $result['success'] ) && ! empty( $result['data'] ) ) {
624 693 // License is valid — update local data
625 694 $this->save( $product_id, $result['data'] );
626 695 } else {