From ee7679d74408f5adb1338d2ae70d12f73f2bdaf5 Mon Sep 17 00:00:00 2001 From: shazzad Date: Thu, 19 Feb 2026 10:46:21 +0600 Subject: [PATCH 1/3] Added renewal url per plugin besides per license --- README.md | 13 ++++++-- src/Admin.php | 4 +-- src/Integration.php | 15 +++++++-- tests/IntegrationLicenseTest.php | 54 ++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6d3612b..d3aee69 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,8 @@ GET /products/{product_id}/details "changelog": "Version history", "installation": "Installation instructions" }, - "download_link": "https://download-url.com/plugin.zip" + "download_link": "https://download-url.com/plugin.zip", + "renewal_url": "https://example.com/renew?license={license_code}&email={email}" } } ``` @@ -156,11 +157,19 @@ GET /products/{product_id}/check_license?license=LICENSE_KEY "status": "active", "expires": "2024-12-31", "customer_name": "John Doe", - "customer_email": "john@example.com" + "customer_email": "john@example.com", + "renewal_url": "https://example.com/renew?license={license_code}&email={email}" } } ``` +The `renewal_url` field is optional and can be provided in either the license verification response or the plugin details response. The license data value takes priority; the details response acts as a fallback. When present and the license status is `expired`, a renewal link is displayed on the admin license page. The URL supports two placeholders that are replaced automatically: + +- `{license_code}` — replaced with the stored license key +- `{email}` — replaced with the `buyer_email` from the license data + +A static URL without placeholders (e.g., `https://example.com/renew`) is also supported. + ### Ping Endpoint ``` diff --git a/src/Admin.php b/src/Admin.php index bcc2460..9c0b0e6 100644 --- a/src/Admin.php +++ b/src/Admin.php @@ -295,7 +295,7 @@ private function render_details_with_license( $details ) { ); } else { if ( 'expired' === $this->integration->get_license_status() ) { - $renewal_url = $this->integration->get_license_renewal_url(); + $renewal_url = $this->integration->get_license_renewal_url( $details ); if ( $renewal_url ) { $output .= \sprintf( 'Your license has expired. Renew your license to get updates.', @@ -328,7 +328,7 @@ private function render_details_with_license( $details ) { $output .= '
You are using the latest version of our plugin.
'; if ( 'expired' === $this->integration->get_license_status() ) { - $renewal_url = $this->integration->get_license_renewal_url(); + $renewal_url = $this->integration->get_license_renewal_url( $details ); if ( $renewal_url ) { $output .= \sprintf( '

Your license has expired. Renew your license to get new updates.

', diff --git a/src/Integration.php b/src/Integration.php index 0fddcb0..774e78f 100644 --- a/src/Integration.php +++ b/src/Integration.php @@ -230,12 +230,21 @@ public function get_license_status() { * * @since 1.0 * + * @param array $details Optional. Plugin details from the API, used as fallback source for renewal_url. * @return string Renewal URL or empty string if not available. */ - public function get_license_renewal_url() { + public function get_license_renewal_url( $details = [] ) { $data = $this->get_license_data(); - if ( empty( $data['renewal_url'] ) ) { + // License data takes priority, then details fallback. + $renewal_url = ''; + if ( ! empty( $data['renewal_url'] ) ) { + $renewal_url = $data['renewal_url']; + } elseif ( ! empty( $details['renewal_url'] ) ) { + $renewal_url = $details['renewal_url']; + } + + if ( empty( $renewal_url ) ) { return ''; } @@ -245,7 +254,7 @@ public function get_license_renewal_url() { $this->get_license_code() ? $this->get_license_code() : '', ! empty( $data['buyer_email'] ) ? $data['buyer_email'] : '', ], - $data['renewal_url'] + $renewal_url ); return $url; diff --git a/tests/IntegrationLicenseTest.php b/tests/IntegrationLicenseTest.php index 79af241..d17c13b 100644 --- a/tests/IntegrationLicenseTest.php +++ b/tests/IntegrationLicenseTest.php @@ -231,4 +231,58 @@ public function get_license_renewal_url_returns_url_without_placeholders() { $integration->get_license_renewal_url() ); } + + /** @test */ + public function get_license_renewal_url_falls_back_to_details() { + $integration = $this->create_integration(); + + Functions\when( 'get_option' )->alias( function ( $key ) { + if ( 'my-plugin42_data' === $key ) { + return [ + 'status' => 'expired', + 'buyer_email' => 'user@example.com', + ]; + } + if ( 'my-plugin42_code' === $key ) { + return 'ABC-123-DEF'; + } + return false; + } ); + + $details = [ + 'renewal_url' => 'https://example.com/renew?license={license_code}&email={email}', + ]; + + $this->assertSame( + 'https://example.com/renew?license=ABC-123-DEF&email=user@example.com', + $integration->get_license_renewal_url( $details ) + ); + } + + /** @test */ + public function get_license_renewal_url_prefers_license_over_details() { + $integration = $this->create_integration(); + + Functions\when( 'get_option' )->alias( function ( $key ) { + if ( 'my-plugin42_data' === $key ) { + return [ + 'renewal_url' => 'https://license.example.com/renew', + 'buyer_email' => 'user@example.com', + ]; + } + if ( 'my-plugin42_code' === $key ) { + return 'ABC-123-DEF'; + } + return false; + } ); + + $details = [ + 'renewal_url' => 'https://details.example.com/renew', + ]; + + $this->assertSame( + 'https://license.example.com/renew', + $integration->get_license_renewal_url( $details ) + ); + } } From a5ff040937ca494c2e2615196206d36fc308d24e Mon Sep 17 00:00:00 2001 From: shazzad Date: Thu, 19 Feb 2026 11:27:05 +0600 Subject: [PATCH 2/3] Refactor get_license_renewal_url to remove details parameter and simplify logic --- src/Admin.php | 4 +-- src/Integration.php | 15 ++------- tests/IntegrationLicenseTest.php | 53 -------------------------------- 3 files changed, 5 insertions(+), 67 deletions(-) diff --git a/src/Admin.php b/src/Admin.php index 9c0b0e6..bcc2460 100644 --- a/src/Admin.php +++ b/src/Admin.php @@ -295,7 +295,7 @@ private function render_details_with_license( $details ) { ); } else { if ( 'expired' === $this->integration->get_license_status() ) { - $renewal_url = $this->integration->get_license_renewal_url( $details ); + $renewal_url = $this->integration->get_license_renewal_url(); if ( $renewal_url ) { $output .= \sprintf( 'Your license has expired. Renew your license to get updates.', @@ -328,7 +328,7 @@ private function render_details_with_license( $details ) { $output .= '
You are using the latest version of our plugin.
'; if ( 'expired' === $this->integration->get_license_status() ) { - $renewal_url = $this->integration->get_license_renewal_url( $details ); + $renewal_url = $this->integration->get_license_renewal_url(); if ( $renewal_url ) { $output .= \sprintf( '

Your license has expired. Renew your license to get new updates.

', diff --git a/src/Integration.php b/src/Integration.php index 774e78f..0fddcb0 100644 --- a/src/Integration.php +++ b/src/Integration.php @@ -230,21 +230,12 @@ public function get_license_status() { * * @since 1.0 * - * @param array $details Optional. Plugin details from the API, used as fallback source for renewal_url. * @return string Renewal URL or empty string if not available. */ - public function get_license_renewal_url( $details = [] ) { + public function get_license_renewal_url() { $data = $this->get_license_data(); - // License data takes priority, then details fallback. - $renewal_url = ''; - if ( ! empty( $data['renewal_url'] ) ) { - $renewal_url = $data['renewal_url']; - } elseif ( ! empty( $details['renewal_url'] ) ) { - $renewal_url = $details['renewal_url']; - } - - if ( empty( $renewal_url ) ) { + if ( empty( $data['renewal_url'] ) ) { return ''; } @@ -254,7 +245,7 @@ public function get_license_renewal_url( $details = [] ) { $this->get_license_code() ? $this->get_license_code() : '', ! empty( $data['buyer_email'] ) ? $data['buyer_email'] : '', ], - $renewal_url + $data['renewal_url'] ); return $url; diff --git a/tests/IntegrationLicenseTest.php b/tests/IntegrationLicenseTest.php index d17c13b..67532eb 100644 --- a/tests/IntegrationLicenseTest.php +++ b/tests/IntegrationLicenseTest.php @@ -232,57 +232,4 @@ public function get_license_renewal_url_returns_url_without_placeholders() { ); } - /** @test */ - public function get_license_renewal_url_falls_back_to_details() { - $integration = $this->create_integration(); - - Functions\when( 'get_option' )->alias( function ( $key ) { - if ( 'my-plugin42_data' === $key ) { - return [ - 'status' => 'expired', - 'buyer_email' => 'user@example.com', - ]; - } - if ( 'my-plugin42_code' === $key ) { - return 'ABC-123-DEF'; - } - return false; - } ); - - $details = [ - 'renewal_url' => 'https://example.com/renew?license={license_code}&email={email}', - ]; - - $this->assertSame( - 'https://example.com/renew?license=ABC-123-DEF&email=user@example.com', - $integration->get_license_renewal_url( $details ) - ); - } - - /** @test */ - public function get_license_renewal_url_prefers_license_over_details() { - $integration = $this->create_integration(); - - Functions\when( 'get_option' )->alias( function ( $key ) { - if ( 'my-plugin42_data' === $key ) { - return [ - 'renewal_url' => 'https://license.example.com/renew', - 'buyer_email' => 'user@example.com', - ]; - } - if ( 'my-plugin42_code' === $key ) { - return 'ABC-123-DEF'; - } - return false; - } ); - - $details = [ - 'renewal_url' => 'https://details.example.com/renew', - ]; - - $this->assertSame( - 'https://license.example.com/renew', - $integration->get_license_renewal_url( $details ) - ); - } } From 56e54cd53bd3ba96e13ef22cd5d1880cfcb9a31a Mon Sep 17 00:00:00 2001 From: shazzad Date: Thu, 19 Feb 2026 11:29:34 +0600 Subject: [PATCH 3/3] Update README to clarify renewal_url field usage in license verification response --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d3aee69..a921097 100644 --- a/README.md +++ b/README.md @@ -137,8 +137,7 @@ GET /products/{product_id}/details "changelog": "Version history", "installation": "Installation instructions" }, - "download_link": "https://download-url.com/plugin.zip", - "renewal_url": "https://example.com/renew?license={license_code}&email={email}" + "download_link": "https://download-url.com/plugin.zip" } } ``` @@ -163,7 +162,7 @@ GET /products/{product_id}/check_license?license=LICENSE_KEY } ``` -The `renewal_url` field is optional and can be provided in either the license verification response or the plugin details response. The license data value takes priority; the details response acts as a fallback. When present and the license status is `expired`, a renewal link is displayed on the admin license page. The URL supports two placeholders that are replaced automatically: +The `renewal_url` field is optional in the license verification response. When present and the license status is `expired`, a renewal link is displayed on the admin license page. The URL supports two placeholders that are replaced automatically: - `{license_code}` — replaced with the stored license key - `{email}` — replaced with the `buyer_email` from the license data