← All changes
|
admin/pages/license/src/Services/ActionsService.php
+62
-2
3.2.1
→
3.2.2
View file →
| @@ -50,8 +50,9 @@ | ||
| 50 | 50 | add_action( $p . 'activate_addon', [ $this, 'ajax_activate_addon' ] ); |
| 51 | 51 | add_action( $p . 'deactivate_addon', [ $this, 'ajax_deactivate_addon' ] ); |
| 52 | 52 | add_action( $p . 'install_activate_addon', [ $this, 'ajax_install_activate_addon' ] ); |
| 53 | 53 | add_action( $p . 'download_addon', [ $this, 'ajax_download_addon' ] ); |
| 54 | + add_action( $p . 'install_verified_copy', [ $this, 'ajax_install_verified_copy' ] ); | |
| 54 | 55 | |
| 55 | 56 | // Subscription |
| 56 | 57 | add_action( $p . 'cancel_subscription', [ $this, 'ajax_cancel_subscription' ] ); |
| 57 | 58 | add_action( $p . 'resume_subscription', [ $this, 'ajax_resume_subscription' ] ); |
| @@ -106,8 +107,12 @@ | ||
| 106 | 107 | } |
| 107 | 108 | $pid = $product['id']; |
| 108 | 109 | $is_bundle = ! empty( $product['is_bundle'] ); |
| 109 | 110 | |
| 111 | + // Marketing links from the Paddle product custom attributes (empty = no button on the card) | |
| 112 | + $product['product_url'] = $this->product_link( $product, 'product_url' ); | |
| 113 | + $product['demo_url'] = $this->product_link( $product, 'demo_url' ); | |
| 114 | + | |
| 110 | 115 | // For bundle products, check if all included addons are licensed |
| 111 | 116 | if( $is_bundle && ! empty( $product['bundle_slugs'] ) ) { |
| 112 | 117 | $bundle_all_licensed = true; |
| 113 | 118 | $bundle_addon_names = []; |
| @@ -185,8 +190,13 @@ | ||
| 185 | 190 | } |
| 186 | 191 | $can_install = ! $needs_install || $this->addonsService->can_install_addons(); |
| 187 | 192 | foreach( $products as &$product ) { |
| 188 | 193 | $product['can_install'] = $can_install; |
| 194 | + // Download ZIP is offered only when WordPress can't install a licensed addon (admin.js also sets it after an install fails for that reason) | |
| 195 | + $product['offer_download'] = ! $can_install && ( $product['is_licensed'] || $product['is_trial'] ) && empty( $product['is_bundle'] ) && $product['addon_status'] === 'not_installed'; | |
| 196 | + // "Reinstall Addon" for every installed licensed addon; emphasized when the installed copy isn't verified | |
| 197 | + $product['offer_verified_copy'] = ( $product['is_licensed'] || $product['is_trial'] ) && empty( $product['is_bundle'] ) && $product['addon_status'] !== 'not_installed'; | |
| 198 | + $product['needs_verified_copy'] = $product['offer_verified_copy'] && $this->addonsService->needs_verified_copy( $product['plugin_slug'] ?? '' ); | |
| 189 | 199 | } |
| 190 | 200 | unset( $product ); |
| 191 | 201 | |
| 192 | 202 | $products = array_values( $products ); |
| @@ -195,8 +205,18 @@ | ||
| 195 | 205 | wp_send_json_error( [ 'message' => __( 'Failed to load products', 'gvectors' ) ] ); |
| 196 | 206 | } |
| 197 | 207 | } |
| 198 | 208 | |
| 209 | + /** | |
| 210 | + * A link from the product's Paddle custom data (http/https only) — '' when missing, empty or not a web URL. | |
| 211 | + */ | |
| 212 | + private function product_link( array $product, string $key ): string { | |
| 213 | + $url = $product['custom_data'][ $key ] ?? ''; | |
| 214 | + if( ! is_string( $url ) || ( $url = trim( $url ) ) === '' ) return ''; | |
| 215 | + | |
| 216 | + return esc_url_raw( $url, [ 'http', 'https' ] ); | |
| 217 | + } | |
| 218 | + | |
| 199 | 219 | private function verify_admin(): bool { |
| 200 | 220 | if( ! current_user_can( 'administrator' ) ) { |
| 201 | 221 | wp_send_json_error( [ 'message' => __( 'Permission denied', 'gvectors' ) ] ); |
| 202 | 222 | |
| @@ -512,11 +532,12 @@ | ||
| 512 | 532 | $response = $this->addonsService->licenseService->activate( $license_key, $product_id ); |
| 513 | 533 | if( ! empty( $response['success'] ) ) { |
| 514 | 534 | // Revalidate all licenses to clear expired notices for newly purchased/renewed addons |
| 515 | 535 | $this->addonsService->check_all_license_validity(); |
| 536 | + $this->addonsService->reverify_licensed_addons(); | |
| 516 | 537 | wp_send_json_success( [ |
| 517 | 538 | 'license' => $response['data'], |
| 518 | - 'message' => __( 'License activated successfully', 'gvectors' ), | |
| 539 | + 'message' => self::activated_message( $response['data'] ), | |
| 519 | 540 | ] ); |
| 520 | 541 | } else { |
| 521 | 542 | $error = $response['error'] ?? __( 'Failed to activate license', 'gvectors' ); |
| 522 | 543 | wp_send_json_error( [ 'message' => $error ] ); |
| @@ -537,8 +558,9 @@ | ||
| 537 | 558 | |
| 538 | 559 | $response = $this->addonsService->licenseService->activate_by_transaction( $transaction_id, $product_id ); |
| 539 | 560 | if( ! empty( $response['success'] ) ) { |
| 540 | 561 | $this->addonsService->check_all_license_validity(); |
| 562 | + $this->addonsService->reverify_licensed_addons(); | |
| 541 | 563 | wp_send_json_success( [ |
| 542 | 564 | 'activated' => $response['data']['activated'] ?? [], |
| 543 | 565 | 'errors' => $response['data']['errors'] ?? [], |
| 544 | 566 | 'message' => $response['data']['message'] ?? __( 'Licenses activated successfully', 'gvectors' ), |
| @@ -559,8 +581,9 @@ | ||
| 559 | 581 | $response = $this->addonsService->licenseService->activate_unified( $key, $product_id ); |
| 560 | 582 | |
| 561 | 583 | if( ! empty( $response['success'] ) ) { |
| 562 | 584 | $this->addonsService->check_all_license_validity(); |
| 585 | + $this->addonsService->reverify_licensed_addons(); | |
| 563 | 586 | // Multi-license response (txn_* or by-domain) |
| 564 | 587 | if( ! empty( $response['data']['activated'] ) ) { |
| 565 | 588 | wp_send_json_success( [ |
| 566 | 589 | 'activated' => $response['data']['activated'], |
| @@ -570,9 +593,9 @@ | ||
| 570 | 593 | } else { |
| 571 | 594 | // Single license response (gvl_* or legacy key) |
| 572 | 595 | wp_send_json_success( [ |
| 573 | 596 | 'license' => $response['data'], |
| 574 | - 'message' => __( 'License activated successfully', 'gvectors' ), | |
| 597 | + 'message' => self::activated_message( $response['data'] ), | |
| 575 | 598 | ] ); |
| 576 | 599 | } |
| 577 | 600 | |
| 578 | 601 | return; |
| @@ -580,8 +603,20 @@ | ||
| 580 | 603 | |
| 581 | 604 | wp_send_json_error( [ 'message' => $response['error'] ?? __( 'Could not activate. Please check your key.', 'gvectors' ) ] ); |
| 582 | 605 | } |
| 583 | 606 | |
| 607 | + /** | |
| 608 | + * Success message for a single activated license. An expired old-store key is still linked to the site | |
| 609 | + * (the addon keeps working), but it grants no updates until renewed. | |
| 610 | + */ | |
| 611 | + private static function activated_message( $license ): string { | |
| 612 | + if( is_array( $license ) && ( $license['status'] ?? '' ) === 'expired' ) { | |
| 613 | + return __( 'Your license was linked to this site. It has expired: the addon keeps working, renew it to get updates.', 'gvectors' ); | |
| 614 | + } | |
| 615 | + | |
| 616 | + return __( 'License activated successfully', 'gvectors' ); | |
| 617 | + } | |
| 618 | + | |
| 584 | 619 | public function ajax_activate_by_domain(): void { |
| 585 | 620 | if( ! $this->verify_admin() ) return; |
| 586 | 621 | |
| 587 | 622 | $response = $this->addonsService->licenseService->activate_by_domain(); |
| @@ -586,8 +621,9 @@ | ||
| 586 | 621 | |
| 587 | 622 | $response = $this->addonsService->licenseService->activate_by_domain(); |
| 588 | 623 | if( ! empty( $response['success'] ) ) { |
| 589 | 624 | $this->addonsService->check_all_license_validity(); |
| 625 | + $this->addonsService->reverify_licensed_addons(); | |
| 590 | 626 | wp_send_json_success( [ |
| 591 | 627 | 'activated' => $response['data']['activated'] ?? [], |
| 592 | 628 | 'errors' => $response['data']['errors'] ?? [], |
| 593 | 629 | 'message' => $response['data']['message'] ?? __( 'Licenses activated successfully', 'gvectors' ), |
| @@ -737,8 +773,32 @@ | ||
| 737 | 773 | wp_send_json_success( $result ); |
| 738 | 774 | } else { |
| 739 | 775 | wp_send_json_error( [ |
| 740 | 776 | 'message' => $result['error'] ?? __( 'Install & activate failed', 'gvectors' ), |
| 777 | + 'manual_install' => ! empty( $result['manual_install'] ), | |
| 778 | + ] ); | |
| 779 | + } | |
| 780 | + } | |
| 781 | + | |
| 782 | + /** | |
| 783 | + * "Reinstall Addon": replace an installed licensed addon with a fresh copy signed for this site | |
| 784 | + */ | |
| 785 | + public function ajax_install_verified_copy(): void { | |
| 786 | + if( ! $this->verify_admin() ) return; | |
| 787 | + | |
| 788 | + $product_id = isset( $_POST['product_id'] ) ? sanitize_text_field( $_POST['product_id'] ) : ''; | |
| 789 | + if( empty( $product_id ) ) { | |
| 790 | + wp_send_json_error( [ 'message' => __( 'Product ID required', 'gvectors' ) ] ); | |
| 791 | + | |
| 792 | + return; | |
| 793 | + } | |
| 794 | + | |
| 795 | + $result = $this->addonsService->install_verified_copy( $product_id ); | |
| 796 | + if( ! empty( $result['success'] ) ) { | |
| 797 | + wp_send_json_success( $result ); | |
| 798 | + } else { | |
| 799 | + wp_send_json_error( [ | |
| 800 | + 'message' => $result['error'] ?? __( 'Could not reinstall the addon', 'gvectors' ), | |
| 741 | 801 | 'manual_install' => ! empty( $result['manual_install'] ), |
| 742 | 802 | ] ); |
| 743 | 803 | } |
| 744 | 804 | } |