From 0e6253348c2b54294d792b1acfba9a4b3fff6bd7 Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Fri, 12 Jan 2024 11:04:55 +0800 Subject: [PATCH 1/7] docs MVP --- integration/docs/generic.md | 245 +++++++++++++++++++----------------- 1 file changed, 130 insertions(+), 115 deletions(-) diff --git a/integration/docs/generic.md b/integration/docs/generic.md index d62ba52..f1d5ab7 100644 --- a/integration/docs/generic.md +++ b/integration/docs/generic.md @@ -16,47 +16,37 @@ Also of note, in the context of a generic package, the "domain" added to or remo * [WP Packages Update Server - Generic Updates Integration - Developer documentation](#wp-packages-update-server---generic-updates-integration---developer-documentation) * [Using the provided examples](#using-the-provided-examples) - * [Requesting update information](#requesting-update-information) - * [Parameters](#parameters) - * [Sample url](#sample-url) - * [Example response](#example-response) - * [Examples request](#examples-request) - * [Wordpress](#wordpress) - * [PHP Curl](#php-curl) - * [Node.js](#nodejs) - * [JavaScript](#javascript) - * [Python](#python) - * [Bash curl](#bash-curl) + * [Disclaimer](#disclaimer) + * [Configuration](#configuration) + * [Usage](#usage) + * [API](#api) + * [Requesting update information](#requesting-update-information) + * [Parameters](#parameters) + * [Sample url](#sample-url) + * [Example response](#example-response) + * [Examples request](#examples-request) * [Activating/Deactivating a license](#activatingdeactivating-a-license) - * [Parameters](#parameters-1) - * [Sample urls](#sample-urls) - * [Example response](#example-response-1) - * [Examples request](#examples-request-1) - * [Wordpress](#wordpress-1) - * [PHP Curl](#php-curl-1) - * [Node.js](#nodejs-1) - * [JavaScript](#javascript-1) - * [Python](#python-1) - * [Bash curl](#bash-curl-1) + * [Parameters](#parameters-1) + * [Sample urls](#sample-urls) + * [Example response](#example-response-1) + * [Examples request](#examples-request-1) * [Downloading a package](#downloading-a-package) - * [Parameters](#parameters-2) - * [Sample url](#sample-url-1) - * [Example response](#example-response-2) - * [Examples request](#examples-request-2) - * [Wordpress](#wordpress-2) - * [PHP Curl](#php-curl-2) - * [Node.js](#nodejs-2) - * [JavaScript](#javascript-2) - * [Python](#python-2) - * [Bash curl](#bash-curl-2) + * [Parameters](#parameters-2) + * [Sample url](#sample-url-1) + * [Example response](#example-response-2) + * [Examples request](#examples-request-2) ## Using the provided examples Examples of implementations in Node.js, PHP, Bash, and Python are provided in `wp-content/plugins/wp-packages-update-server/integration/dummy-generic`. -Although the can be executed, the examples are meant to be used as a starting point for your own implementation, and are **not meant to be used as-is**. +Although they can be executed, the examples are meant to be used as a starting point for your own implementation, and are **not meant to be used as-is**. +All the examples have been tested on Linux and MacOS. + +### Disclaimer + Each `wppus-api.[js|php|sh|py]` file contains a header with the following disclaimer: -``` +```php ### EXAMPLE INTEGRATION WITH WP PACKAGES UPDATE SERVER ### # DO NOT USE THIS FILE AS IT IS IN PRODUCTION !!! @@ -69,6 +59,8 @@ Each `wppus-api.[js|php|sh|py]` file contains a header with the following discla # WP Packages Update Server is installed in wppus.json ``` +### Configuration + Example of package configuration file `wppus.json` (all properties required except `requireLicense` which defaults to `false`): ```json @@ -86,9 +78,11 @@ Example of package configuration file `wppus.json` (all properties required exce } ``` -Use the example by typing: +### Usage -``` +In a terminal, use the example by typing (replace `[js|php|sh|py]` with the extension of the file you want to test): + +```bash cd wp-content/plugins/wp-packages-update-server/integration/dummy-generic # show the help ./dummy-generic.[js|php|sh|py] @@ -108,7 +102,7 @@ cd wp-content/plugins/wp-packages-update-server/integration/dummy-generic Typing `./dummy-generic.[js|php|sh|py]` without any argument will display the help: -``` +```bash Usage: ./dummy-generic.[js|php|sh|py] [command] [arguments] Commands: install [license] - install the package @@ -121,9 +115,11 @@ Commands: Note: this package assumes it needs a license. ``` -## Requesting update information +## API + +### Requesting update information -### Parameters +#### Parameters | Parameter | Required | Description | | --- | --- | --- | @@ -134,13 +130,13 @@ Note: this package assumes it needs a license. | license_signature | no | The license signature of the package, saved by the client | | update_type | yes | The type of the update - `Generic` | -### Sample url +#### Sample url ``` -https://server.domain.tld/wppus-update-api/?action=get_metadata&package_id=dummy-generic-package&installed_version=1.4.13&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D&update_type=Generic +https://server.domain.tld/wppus-update-api/?action=get_metadata&package_id=dummy-generic&installed_version=1.4.13&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D&update_type=Generic ``` -### Example response +#### Example response Raw - usable result depends on the language & framework used to get the response. Only the relevant headers are shown here. @@ -155,13 +151,13 @@ HTTP/1.1 200 OK { "name": "Dummy Generic Package", "version": "1.4.14", - "homepage": "https:\/\/dev.tld\/", - "author": "Alexandre Froger", - "author_homepage": "https:\/\/dev.tld", + "homepage": "https:\/\/domain.tld\/", + "author": "Developer Name", + "author_homepage": "https:\/\/domain.tld\/", "description": "Empty Generic Package", "last_updated": "2024-01-01 00:00:00", - "slug": "dummy-generic-package", - "download_url": "https:\/\/server.domain.tld\/wppus-update-api\/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package", + "slug": "dummy-generic", + "download_url": "https:\/\/server.domain.tld\/wppus-update-api\/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic", "request_time_elapsed": "0.386" } @@ -176,12 +172,12 @@ HTTP/1.1 200 OK { "name": "Dummy Generic Package", "version": "1.4.14", - "homepage": "https:\/\/dev.tld\/", - "author": "Alexandre Froger", - "author_homepage": "https:\/\/dev.tld", + "homepage": "https:\/\/domain.tld\/", + "author": "Developer Name", + "author_homepage": "https:\/\/domain.tld\/", "description": "Empty Generic Package", "last_updated": "2024-01-01 00:00:00", - "slug": "dummy-generic-package", + "slug": "dummy-generic", "license_error": {}, "request_time_elapsed": "0.386" } @@ -194,13 +190,13 @@ In case a valid license key is provided: { "name": "Dummy Generic Package", "version": "1.4.14", - "homepage": "https:\/\/dev.tld\/", - "author": "Alexandre Froger", - "author_homepage": "https:\/\/dev.tld", + "homepage": "https:\/\/domain.tld\/", + "author": "Developer Name", + "author_homepage": "https:\/\/domain.tld\/", "description": "Empty Generic Package", "last_updated": "2024-01-01 00:00:00", - "slug": "dummy-generic-package", - "download_url": "https:\/\/server.domain.tld\/wppus-update-api\/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D", + "slug": "dummy-generic", + "download_url": "https:\/\/server.domain.tld\/wppus-update-api\/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D", "license": { "id": "9999", "license_key": "41ec1eba0f17d47f76827a33c7daab2c", @@ -213,25 +209,25 @@ In case a valid license key is provided: "date_created": "2024-01-01", "date_renewed": "0000-00-00", "date_expiry": "2025-01-01", - "package_slug": "dummy-generic-package", + "package_slug": "dummy-generic", "package_type": "generic", "result": "success", "message": "License key details retrieved.", - "product_ref": "dummy-generic-package\/dummy-generic-package.json" + "product_ref": "dummy-generic\/dummy-generic.json" }, "request_time_elapsed": "0.274" } ``` -### Examples request +#### Examples request -#### Wordpress +**Wordpress** ```php $signature = raw_url_encode( 'ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs=' ); $args = array( 'action' => 'get_metadata', - 'package_id' => 'dummy-generic-package', + 'package_id' => 'dummy-generic', 'installed_version' => '1.4.13', 'license_key' => '41ec1eba0f17d47f76827a33c7daab2c', 'license_signature' => $signature, @@ -249,13 +245,13 @@ $response = wp_remote_get( ); ``` -#### PHP Curl +**PHP Curl** ```php $signature = raw_url_encode( 'ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs=' ); $args = array( 'action' => 'get_metadata', - 'package_id' => 'dummy-generic-package', + 'package_id' => 'dummy-generic', 'installed_version' => '1.4.13', 'license_key' => '41ec1eba0f17d47f76827a33c7daab2c', 'license_signature' => $signature, @@ -274,7 +270,7 @@ curl_close( $ch ); ``` -#### Node.js +**Node.js** ```js const https = require('https'); @@ -282,7 +278,7 @@ const querystring = require('querystring'); const signature = encodeURIComponent('ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs='); const args = { action: 'get_metadata', - package_id: 'dummy-generic-package', + package_id: 'dummy-generic', installed_version: '1.4.13', license_key: '41ec1eba0f17d47f76827a33c7daab2c', license_signature: signature @@ -313,13 +309,13 @@ https.get(url, options, (res) => { }); ``` -#### JavaScript +**JavaScript** ```js const signature = encodeURIComponent('ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs='); const args = { action: 'get_metadata', - package_id: 'dummy-generic-package', + package_id: 'dummy-generic', installed_version: '1.4.13', license_key: '41ec1eba0f17d47f76827a33c7daab2c', license_signature: signature, @@ -344,7 +340,7 @@ fetch(url, { ``` -#### Python +**Python** ```python import requests @@ -353,7 +349,7 @@ import urllib.parse signature = urllib.parse.quote_plus('ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs=') args = { 'action': 'get_metadata', - 'package_id': 'dummy-generic-package', + 'package_id': 'dummy-generic', 'installed_version': '1.4.13', 'license_key': '41ec1eba0f17d47f76827a33c7daab2c', 'license_signature': signature, @@ -368,16 +364,35 @@ else: print('Error:', response.status_code) ``` -#### Bash curl +**Bash curl** ```bash #!/bin/bash -signature=$(echo -n 'ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs=' | perl -MURI::Escape -ne 'print uri_escape($_)') +function urlencode() { + local old_lc_collate=$LC_COLLATE + + LC_COLLATE=C + + local length="${#1}" + + for (( i = 0; i < length; i++ )); do + local c="${1:$i:1}" + + case $c in + [a-zA-Z0-9.~_-]) printf '%s' "$c" ;; + *) printf '%%%02X' "'$c" ;; + esac + done + + LC_COLLATE=$old_lc_collate +} + +signature=$(urlencode "ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs=") url="https://server.domain.tld/wppus-update-api/" args=( "action=get_metadata" - "package_id=dummy-generic-package" + "package_id=dummy-generic" "installed_version=1.4.13" "license_key=41ec1eba0f17d47f76827a33c7daab2c" "license_signature=$signature" @@ -391,7 +406,7 @@ echo "$response" ### Activating/Deactivating a license -### Parameters +#### Parameters | Parameter | Required | Description | | --- | --- | --- | @@ -401,20 +416,20 @@ echo "$response" | package_slug | yes | The package identifier | -### Sample urls +#### Sample urls Activation: ``` -https://server.domain.tld/wppus-update-api/?action=activate&license_key=41ec1eba0f17d47f76827a33c7daab2c&allowed_domains=allowedClientIdentifier&package_slug=dummy-generic-package +https://server.domain.tld/wppus-update-api/?action=activate&license_key=41ec1eba0f17d47f76827a33c7daab2c&allowed_domains=allowedClientIdentifier&package_slug=dummy-generic ``` ___ Deactivation: ``` -https://server.domain.tld/wppus-update-api/?action=deactivate&license_key=41ec1eba0f17d47f76827a33c7daab2c&allowed_domains=allowedClientIdentifier&package_slug=dummy-generic-package +https://server.domain.tld/wppus-update-api/?action=deactivate&license_key=41ec1eba0f17d47f76827a33c7daab2c&allowed_domains=allowedClientIdentifier&package_slug=dummy-generic ``` -### Example response +#### Example response Raw - usable result depends on the language & framework used to get the response. Only the relevant headers are shown here. @@ -425,7 +440,7 @@ Success - activation: ``` HTTP/1.1 200 OK -{"license_key":"41ec1eba0f17d47f76827a33c7daab2c","max_allowed_domains":999,"allowed_domains":["allowedClientIdentifier"],"status":"activated","txn_id":"","date_created":"2024-01-01","date_renewed":"0000-00-00","date_expiry":"2025-01-01","package_slug":"dummy-generic-package","package_type":"generic","license_signature":"ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs="} +{"license_key":"41ec1eba0f17d47f76827a33c7daab2c","max_allowed_domains":999,"allowed_domains":["allowedClientIdentifier"],"status":"activated","txn_id":"","date_created":"2024-01-01","date_renewed":"0000-00-00","date_expiry":"2025-01-01","package_slug":"dummy-generic","package_type":"generic","license_signature":"ZaH+a_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs="} ``` This is when the license signature must be saved by the client to be used for future update requests. @@ -436,7 +451,7 @@ Success - deactivation: ``` HTTP/1.1 200 OK -{"license_key":"41ec1eba0f17d47f76827a33c7daab2c","max_allowed_domains":999,"allowed_domains":[],"status":"deactivated","txn_id":"","date_created":"2024-01-01","date_renewed":"0000-00-00","date_expiry":"2025-01-01","package_slug":"dummy-generic-package","package_type":"generic"} +{"license_key":"41ec1eba0f17d47f76827a33c7daab2c","max_allowed_domains":999,"allowed_domains":[],"status":"deactivated","txn_id":"","date_created":"2024-01-01","date_renewed":"0000-00-00","date_expiry":"2025-01-01","package_slug":"dummy-generic","package_type":"generic"} ``` ___ @@ -472,16 +487,16 @@ HTTP/1.1 400 Bad Request {"max_allowed_domains":"2"} ``` -### Examples request +#### Examples request -#### Wordpress +**Wordpress** ```php $args = array( 'action' => 'activate', // or 'deactivate' 'license_key' => '41ec1eba0f17d47f76827a33c7daab2c', 'allowed_domains' => 'allowedClientIdentifier', - 'package_slug' => 'dummy-generic-package', + 'package_slug' => 'dummy-generic', ); $url = add_query_arg( $args, 'https://server.domain.tld/wppus-license-api/' ); @@ -494,14 +509,14 @@ wp_remote_get( ); ``` -#### PHP Curl +**PHP Curl** ```php $args = array( 'action' => 'activate', // or 'deactivate' 'license_key' => '41ec1eba0f17d47f76827a33c7daab2c', 'allowed_domains' => 'allowedClientIdentifier', - 'package_slug' => 'dummy-generic-package', + 'package_slug' => 'dummy-generic', ); $url = 'https://server.domain.tld/wppus-license-api/?' . http_build_query($args); @@ -516,7 +531,7 @@ $response = curl_exec($ch); curl_close($ch); ``` -#### Node.js +**Node.js** ```js const https = require('https'); @@ -525,7 +540,7 @@ const args = { action: 'activate', // or 'deactivate' license_key: '41ec1eba0f17d47f76827a33c7daab2c', allowed_domains: 'allowedClientIdentifier', - package_slug: 'dummy-generic-package', + package_slug: 'dummy-generic', }; const url = 'https://server.domain.tld/wppus-license-api/?' + querystring.stringify(args); @@ -547,14 +562,14 @@ https.get(url, (res) => { }); ``` -#### JavaScript +**JavaScript** ```js const args = { action: 'activate', // or 'deactivate' license_key: '41ec1eba0f17d47f76827a33c7daab2c', allowed_domains: 'allowedClientIdentifier', - package_slug: 'dummy-generic-package', + package_slug: 'dummy-generic', }; const url = new URL('https://server.domain.tld/wppus-license-api/'); @@ -570,7 +585,7 @@ fetch(url) }); ``` -#### Python +**Python** ```python import requests @@ -580,7 +595,7 @@ args = { 'action': 'activate', # or 'deactivate' 'license_key': '41ec1eba0f17d47f76827a33c7daab2c', 'allowed_domains': 'allowedClientIdentifier', - 'package_slug': 'dummy-generic-package', + 'package_slug': 'dummy-generic', } url = 'https://server.domain.tld/wppus-license-api/?' + urllib.parse.urlencode(args) @@ -593,7 +608,7 @@ except requests.exceptions.HTTPError as err: print(f'Error: {err}') ``` -#### Bash curl +**Bash curl** ```bash #!/bin/bash @@ -603,7 +618,7 @@ args=( "action=activate" "license_key=41ec1eba0f17d47f76827a33c7daab2c" "allowed_domains=allowedClientIdentifier" - "package_slug=dummy-generic-package" + "package_slug=dummy-generic" ) full_url="${url}?$(IFS=\& ; echo "${args[*]}")" response=$(curl -s "$full_url") @@ -615,7 +630,7 @@ echo $response Note: the download URL with its one-time use token is acquired from the response to the `get_metadata` API call (see [Requesting update information](#requesting-update-information)). -### Parameters +#### Parameters | Parameter | Required | Description | | --- | --- | --- | @@ -625,13 +640,13 @@ Note: the download URL with its one-time use token is acquired from the response | license_key | no | The license key of the package, saved by the client | | license_signature | no | The license signature of the package, saved by the client | -### Sample url +#### Sample url ``` -https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D +https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D ``` -### Example response +#### Example response Raw - usable result depends on the language & framework used to get the response. Only the relevant headers are shown here. @@ -663,7 +678,7 @@ HTTP/1.1 403 Forbidden 403 Forbidden -

403 Forbidden

+

403 Forbidden

Invalid license key or signature.

``` ___ @@ -678,12 +693,12 @@ HTTP/1.1 404 Not Found ``` -### Examples request +#### Examples request -#### Wordpress +**Wordpress** ```php -$download_url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; +$download_url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; $response = wp_remote_get( $download_url, array( @@ -702,14 +717,14 @@ if ( 200 === wp_remote_retrieve_response_code( $response ) ) { WP_Filesystem(); } - $wp_filesystem->put_contents( '/tmp/dummy-generic-package.zip', $package, FS_CHMOD_FILE ); + $wp_filesystem->put_contents( '/tmp/dummy-generic.zip', $package, FS_CHMOD_FILE ); } ``` -#### PHP Curl +**PHP Curl** ```php -$download_url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; +$download_url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; $options = [ 'http' => [ 'timeout' => 20, @@ -723,21 +738,21 @@ $context = stream_context_create($options); $response = file_get_contents($download_url, false, $context); if ($http_response_header[0] == 'HTTP/1.1 200 OK') { - file_put_contents('/tmp/dummy-generic-package.zip', $response); + file_put_contents('/tmp/dummy-generic.zip', $response); } ``` -#### Node.js +**Node.js** ```js const https = require('follow-redirects').https; const fs = require('fs'); -const url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; +const url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; https.get(url, (res) => { if (res.statusCode === 200) { - const file = fs.createWriteStream("/tmp/dummy-generic-package.zip"); + const file = fs.createWriteStream("/tmp/dummy-generic.zip"); res.pipe(file); } @@ -746,10 +761,10 @@ https.get(url, (res) => { }); ``` -#### JavaScript +**JavaScript** ```js -const url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; +const url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D"; fetch(url) .then(response => response.blob()) @@ -758,7 +773,7 @@ fetch(url) const a = document.createElement('a'); a.style.display = 'none'; a.href = url; - a.download = 'dummy-generic-package.zip'; + a.download = 'dummy-generic.zip'; document.body.appendChild(a); a.click(); @@ -769,29 +784,29 @@ fetch(url) }); ``` -#### Python +**Python** ```python import requests -url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D" +url = "https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D" response = requests.get(url, stream=True) if response.status_code == 200: - with open('/tmp/dummy-generic-package.zip', 'wb') as f: + with open('/tmp/dummy-generic.zip', 'wb') as f: for chunk in response.iter_content(chunk_size=1024): if chunk: f.write(chunk) else: print(f'Error: HTTP status code {response.status_code}') ``` -#### Bash curl +**Bash curl** ```bash #!/bin/bash -url="https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic-package&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D" -output_file="/tmp/dummy-generic-package.zip" +url="https://server.domain.tld/wppus-update-api/?action=download&token=c0c403841752170640518823d752baba&package_id=dummy-generic&license_key=41ec1eba0f17d47f76827a33c7daab2c&license_signature=ZaH%2Ba_p1_EkM3BUIpqn7T53htuVPBem2lDtGIxr28oHjdCycvo_ZkxItYqb7mOHhfCMSwnMofWW7UchztEo0k2TwRgk81rNvZyYv6GfRZIxzDP5SzgREjnSAu6JVxDa5yvdd6uqWHWi_U1wRxff0nItItoAloWsek1SVbWbmQXs%3D" +output_file="/tmp/dummy-generic.zip" curl -o $output_file $url ``` From d93c986e1b667bbd5b8dcd123158b7f454bb78bc Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Fri, 12 Jan 2024 14:56:07 +0800 Subject: [PATCH 2/7] generalise wp package updater object construction --- integration/dummy-plugin/dummy-plugin.php | 6 +++--- .../class-wp-package-updater.php | 16 +++------------- integration/dummy-theme/functions.php | 6 +++--- .../class-wp-package-updater.php | 16 +++------------- 4 files changed, 12 insertions(+), 32 deletions(-) diff --git a/integration/dummy-plugin/dummy-plugin.php b/integration/dummy-plugin/dummy-plugin.php index 103d532..8cb9fad 100644 --- a/integration/dummy-plugin/dummy-plugin.php +++ b/integration/dummy-plugin/dummy-plugin.php @@ -33,13 +33,13 @@ * **/ -/** Enable updates**/ +/** Enable updates **/ /* phpcs:ignore Squiz.PHP.CommentedOutCode.Found -require_once plugin_dir_path( __FILE__ ) . 'lib/wp-package-updater/class-wp-package-updater.php'; +require_once __DIR__ . '/lib/wp-package-updater/class-wp-package-updater.php'; $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - wp_normalize_path( plugin_dir_path( __FILE__ ) ) + strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ diff --git a/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php b/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php index 523f1c5..a92dc00 100644 --- a/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php +++ b/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php @@ -32,23 +32,13 @@ * Also change $prefix_updater below - replace "prefix" in this variable's name with a unique prefix * -/** Use for plugin updates **/ +/** Enable updates **/ /* phpcs:ignore Squiz.PHP.CommentedOutCode.Found -require_once plugin_dir_path( __FILE__ ) . 'lib/wp-package-updater/class-wp-package-updater.php'; +require_once __DIR__ . '/lib/wp-package-updater/class-wp-package-updater.php'; $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - wp_normalize_path( plugin_dir_path( __FILE__ ) ) -); -*/ - -/** Use for theme updates **/ -/* phpcs:ignore Squiz.PHP.CommentedOutCode.Found -require_once plugin_dir_path( __FILE__ ) . 'lib/wp-package-updater/class-wp-package-updater.php'; - -$prefix_updater = new WP_Package_Updater( - wp_normalize_path( __FILE__ ), - get_stylesheet_directory() + strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ diff --git a/integration/dummy-theme/functions.php b/integration/dummy-theme/functions.php index e74b82d..9461ac7 100644 --- a/integration/dummy-theme/functions.php +++ b/integration/dummy-theme/functions.php @@ -21,13 +21,13 @@ * **/ -/** Enable updates**/ +/** Enable updates **/ /* phpcs:ignore Squiz.PHP.CommentedOutCode.Found -require_once plugin_dir_path( __FILE__ ) . 'lib/wp-package-updater/class-wp-package-updater.php'; +require_once __DIR__ . '/lib/wp-package-updater/class-wp-package-updater.php'; $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - get_stylesheet_directory() + strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ diff --git a/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php b/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php index 523f1c5..a92dc00 100644 --- a/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php +++ b/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php @@ -32,23 +32,13 @@ * Also change $prefix_updater below - replace "prefix" in this variable's name with a unique prefix * -/** Use for plugin updates **/ +/** Enable updates **/ /* phpcs:ignore Squiz.PHP.CommentedOutCode.Found -require_once plugin_dir_path( __FILE__ ) . 'lib/wp-package-updater/class-wp-package-updater.php'; +require_once __DIR__ . '/lib/wp-package-updater/class-wp-package-updater.php'; $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - wp_normalize_path( plugin_dir_path( __FILE__ ) ) -); -*/ - -/** Use for theme updates **/ -/* phpcs:ignore Squiz.PHP.CommentedOutCode.Found -require_once plugin_dir_path( __FILE__ ) . 'lib/wp-package-updater/class-wp-package-updater.php'; - -$prefix_updater = new WP_Package_Updater( - wp_normalize_path( __FILE__ ), - get_stylesheet_directory() + strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ From a624dee4e437f59032cf4e16b9690d6c15f006fb Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Fri, 12 Jan 2024 14:56:16 +0800 Subject: [PATCH 3/7] doc MVP --- README.md | 29 ++- css/admin/main.css | 19 ++ inc/templates/admin/plugin-help-page.php | 257 ++++++++++++++--------- 3 files changed, 204 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 1a312dc..545b0b4 100644 --- a/README.md +++ b/README.md @@ -330,11 +330,36 @@ The following can also be found under the "Help" tab of the WP Packages Update S ### Provide updates with WP Packages Update Server - packages requirements -To link your packages to WP Packages Update Server, and optionally to prevent webmasters from getting updates of your plugins and themes without a license, your plugins and themes need to include some extra code. It is a simple matter of adding a few lines in the main plugin file (for plugins) or in the `functions.php` file (for themes), and provide the necessary libraries in a lib directory at the root of the package. +To link your packages to WP Packages Update Server, and optionally to prevent webmasters from getting updates of your ppackages without a license, your packages need to include some extra code. + +For plugins, and themes, it is fairly straightforward: +- Add a `lib` directory with the `plugin-update-checker` and `wp-update-checker` libraries to the root of the package (provided in `dummy-[plugin|theme]` ; `wp-update-checker` can be customized as you see fit, but `plugin-update-checker` should be left untouched). +- Add the following code to the main plugin file (for plugins) or in the `functions.php` file (for themes) : +```php +/** Enable updates - note the `$prefix_updater` variable: change `prefix` to a unique string for your package **/ +require_once __DIR__ . '/lib/wp-package-updater/class-wp-package-updater.php'; + +$prefix_updater = new WP_Package_Updater( + wp_normalize_path( __FILE__ ), + strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() +); +``` +- Add a `wppus.json` file at the root of the package with the following content - change the value of `"server"` to your own (required), and select a value for `"requireLicense"` (optional): +```json +{ + "server": "https://server.domain.tld/", + "requireLicense": true|false +} +``` +- Connect WPPUS with your repository and prime your package, or manually upload your package to WPPUS. + +For generic packages, the steps involved entirely depend on the language used to write the package and the update process of the target platform. +You may refer to the documentation found [here](https://github.com/froger-me/wp-packages-update-server/blob/main/integration/docs/generic.md) +___ See `wp-content/plugins/wp-packages-update-server/integration/dummy-plugin` for an example of plugin, and `wp-content/plugins/wp-packages-update-server/integration/dummy-theme` for an example of theme. They are fully functionnal and can be used to test all the features of the server with a test client installation of WordPress. -'See `wp-content/plugins/wp-packages-update-server/integration/dummy-generic` for examples of a generic package written in Bash, NodeJS, PHP with Curl, and Python. The API calls made by generic packages to the license API and Update API are the same as the WordPress packages. Unlike the upgrade library provided with plugins & themes, the code found in `wppwus-api.[sh|php|js|py]` files is **NOT ready for production environment and MUST be adapted**. You may refer to the documentation found [here](https://github.com/froger-me/wp-packages-update-server/blob/main/integration/docs/generic.md). +See `wp-content/plugins/wp-packages-update-server/integration/dummy-generic` for examples of a generic package written in Bash, NodeJS, PHP with Curl, and Python. The API calls made by generic packages to the license API and Update API are the same as the WordPress packages. Unlike the upgrade library provided with plugins & themes, the code found in `wppwus-api.[sh|php|js|py]` files is **NOT ready for production environment and MUST be adapted**. Unless "Use Remote Repository Service" is checked in "Remote Sources", you need to manually upload the packages zip archives (and subsequent updates) in `wp-content/wppus/packages` or `CloudStorageUnit://wppus-packages/`. Packages need to be valid WordPress plugin or theme packages, and in the case of a plugin the main plugin file must have the same name as the zip archive. For example, the main plugin file in `package-slug.zip` would be `package-slug.php`. diff --git a/css/admin/main.css b/css/admin/main.css index 07697a0..6eeac4d 100644 --- a/css/admin/main.css +++ b/css/admin/main.css @@ -32,4 +32,23 @@ width: 20px; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; +} + +.wppus-wrap .help-content ul { + display: block; + list-style-type: disc; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 0px; + margin-inline-end: 0px; + padding-inline-start: 40px; +} + +.wppus-wrap .help-content pre { + background: rgba(0,0,0,.07); + direction: ltr; + overflow: auto; + padding: 1em; + display: inline-block; + tab-size: 4; } \ No newline at end of file diff --git a/inc/templates/admin/plugin-help-page.php b/inc/templates/admin/plugin-help-page.php index 0a787fd..6f55140 100644 --- a/inc/templates/admin/plugin-help-page.php +++ b/inc/templates/admin/plugin-help-page.php @@ -3,103 +3,162 @@ } ?>
display_settings_header( '' ); ?> -

-

- functions.php, %2$s is lib, %3$s is main file - esc_html__( 'To link your packages, whether they are WordPress plugins, WordPress themes, or generic packages, to the WP Packages Update Server, and optionally to prevent users from getting updates of your packages without a license, your packages need to include some extra code. For WordPress packages, it is a simple matter of adding a few lines in the main plugin file (for plugins), or in the %1$s file (for themes), and provide the necessary libraries in a %2$s directory at the root of the package.', 'wppus' ), - 'functions.php', - 'lib', - ); - ?> -

-

- integration/dummy-plugin, %2$s is integration/dummy-theme - esc_html__( 'See %1$s for an example of plugin, and %2$ss for an example of theme. They are fully functionnal and can be used to test all the features of the server with a test client installation of WordPress.', 'wppus' ), - '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-plugin', - '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-plugin', - ); - ?> -

-

- integration/dummy-generic, %2$s is `wppus-api.[sh|php|js|py]`, %3$s is is a "here" link to the documentation - esc_html__( 'See %1$s for examples of a generic package written in Bash, NodeJS, PHP with Curl, and Python. The API calls made by generic packages to the license API and Update API are the same as the WordPress packages. Unlike the upgrade library provided with plugins & themes, the code found in %2$s files is NOT ready for production environment and MUST be adapted. You may refer to the documentation found %3$s.', 'wppus' ), - '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-generic', - 'wppwus-api.[sh|php|js|py]', - '' . esc_html__( 'here', 'wppus' ) . '' - ); - ?> -

-

- packages_dir, %2$s is package-slug.zip, %3$s is package-slug.php - esc_html__( 'Unless "Use Remote Repository Service" is checked in "Remote Sources", you need to manually upload the packages zip archives (and subsequent updates) in %1$s. A packages need to a valid generic package, or a valid WordPress plugin or theme package, and in the case of a plugin the main plugin file must have the same name as the zip archive. For example, the main plugin file in %2$s would be %3$s.', 'wppus' ), - '' . esc_html( $packages_dir ) . '', - 'package-slug.zip', - 'package-slug.php', - ); - ?> -

-
-

-

- parse_request - esc_html__( "When the remote clients where your plugins, themes, or generic packages are installed send a request to check for updates, download a package or check or change license status, the current server's WordPress installation is loaded, with its own plugins and themes. This is not optimised if left untouched because unnecessary action and filter hooks that execute before %s action hook are also triggered, even though the request is not designed to produce any on-screen output or further computation.", 'wppus' ), - 'parse_request', - ); - ?> -

-

- optimisation/wppus-endpoint-optimiser.php, %2$s is the MU Plugin's path - esc_html__( 'To solve this, the file %1$s has been automatically copied to %2$s. This effectively creates a Must Use Plugin running before everything else and preventing themes and other plugins from being executed when an update request or a license API request is received by WP Packages Update Server.', 'wppus' ), - '' . esc_html( WPPUS_PLUGIN_PATH . 'optimisation/wppus-endpoint-optimiser.php' ) . '', - '' . esc_html( dirname( dirname( WPPUS_PLUGIN_PATH ) ) . '/mu-plugins/wppus-endpoint-optimiser.php' ) . '', - ); - ?> -

-

- $wppus_doing_update_api_request, %2$s is $wppus_doing_license_api_request, %3$s is $wppus_always_active_plugins, %4$s is functions.php, %5$s is $wppus_bypass_themes, %5$s is false - esc_html__( 'The MU Plugin also provides the global variable %1$s and %2$s that can be tested when adding hooks and filters would you choose to keep some plugins active with %3$s or keep %4$s from themes included with %5$s set to %6$s.', 'wppus' ), - '$wppus_doing_update_api_request', - '$wppus_doing_license_api_request', - '$wppus_always_active_plugins', - 'functions.php', - '$wppus_bypass_themes', - 'false', - ); - ?> -

-
-

-

- ' . esc_html__( 'here', 'wppus' ) . '', - ); - ?> -

-

- ' . esc_html__( 'open an issue on Github', 'wppus' ) . '', - 'wppus-help@anyape.com', - ); - ?> -

+
+

+

+

+ +

+
    +
  • + lib, %2$s is plugin-update-checker, %3$s is wp-update-checker, %4$s is dummy-[plugin|theme], %5$s is wp-update-checker, %6$s is plugin-update-checker + esc_html__( 'Add a %1$s directory with the %2$s and %3$s libraries to the root of the package (provided in %4$s ; %5$s can be customized as you see fit, but %6$s should be left untouched).', 'wppus' ), + 'lib', + 'plugin-update-checker', + 'wp-update-checker', + 'dummy-[plugin|theme]', + 'wp-update-checker', + 'plugin-update-checker', + ); + ?> +
  • +
  • + functions.php + esc_html__( 'Add the following code to the main plugin file (for plugins) or in the %s file (for themes) :', 'wppus' ), + 'functions.php' + ); + ?> +
    /** Enable updates - note the  `$prefix_updater` variable: change `prefix` to a unique string for your package **/
    +require_once __DIR__ . '/lib/wp-package-updater/class-wp-package-updater.php';
    +
    +$prefix_updater = new WP_Package_Updater(
    +	wp_normalize_path( __FILE__ ),
    +	strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory()
    +);
    +
  • +
  • + wppus.json, %2$s is "server" + esc_html__( 'Add a %1$s file at the root of the package with the following content - change the value of %2$s to your own (required), and select a value for %3$s (optional):', 'wppus' ), + 'wppus.json', + '"server"', + '"requireLicense"' + ); + ?> +
    {
    +	"server": "https://server.domain.tld/",
    +	"requireLicense": true|false
    +}
    +
  • +
  • + +
  • +
+

+ +
+ ' . esc_html__( 'here', 'wppus' ) . '' + ); + ?> +

+
+

+ integration/dummy-plugin, %2$s is integration/dummy-theme + esc_html__( 'See %1$s for an example of plugin, and %2$ss for an example of theme. They are fully functionnal and can be used to test all the features of the server with a test client installation of WordPress.', 'wppus' ), + '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-plugin', + '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-plugin', + ); + ?> +

+

+ integration/dummy-generic, %2$s is `wppus-api.[sh|php|js|py]` + esc_html__( 'See %1$s for examples of a generic package written in Bash, NodeJS, PHP with Curl, and Python. The API calls made by generic packages to the license API and Update API are the same as the WordPress packages. Unlike the upgrade library provided with plugins & themes, the code found in %2$s files is NOT ready for production environment and MUST be adapted.', 'wppus' ), + '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-generic', + 'wppus-api.[sh|php|js|py]' + ); + ?> +

+

+ packages_dir, %2$s is package-slug.zip, %3$s is package-slug.php + esc_html__( 'Unless "Use Remote Repository Service" is checked in "Remote Sources", you need to manually upload the packages zip archives (and subsequent updates) in %1$s. A packages need to a valid generic package, or a valid WordPress plugin or theme package, and in the case of a plugin the main plugin file must have the same name as the zip archive. For example, the main plugin file in %2$s would be %3$s.', 'wppus' ), + '' . esc_html( $packages_dir ) . '', + 'package-slug.zip', + 'package-slug.php', + ); + ?> +

+
+

+

+ parse_request + esc_html__( "When the remote clients where your plugins, themes, or generic packages are installed send a request to check for updates, download a package or check or change license status, the current server's WordPress installation is loaded, with its own plugins and themes. This is not optimised if left untouched because unnecessary action and filter hooks that execute before %s action hook are also triggered, even though the request is not designed to produce any on-screen output or further computation.", 'wppus' ), + 'parse_request', + ); + ?> +

+

+ optimisation/wppus-endpoint-optimiser.php, %2$s is the MU Plugin's path + esc_html__( 'To solve this, the file %1$s has been automatically copied to %2$s. This effectively creates a Must Use Plugin running before everything else and preventing themes and other plugins from being executed when an update request or a license API request is received by WP Packages Update Server.', 'wppus' ), + '' . esc_html( WPPUS_PLUGIN_PATH . 'optimisation/wppus-endpoint-optimiser.php' ) . '', + '' . esc_html( dirname( dirname( WPPUS_PLUGIN_PATH ) ) . '/mu-plugins/wppus-endpoint-optimiser.php' ) . '', + ); + ?> +

+

+ $wppus_doing_update_api_request, %2$s is $wppus_doing_license_api_request, %3$s is $wppus_always_active_plugins, %4$s is functions.php, %5$s is $wppus_bypass_themes, %5$s is false + esc_html__( 'The MU Plugin also provides the global variable %1$s and %2$s that can be tested when adding hooks and filters would you choose to keep some plugins active with %3$s or keep %4$s from themes included with %5$s set to %6$s.', 'wppus' ), + '$wppus_doing_update_api_request', + '$wppus_doing_license_api_request', + '$wppus_always_active_plugins', + 'functions.php', + '$wppus_bypass_themes', + 'false', + ); + ?> +

+
+

+

+ ' . esc_html__( 'here', 'wppus' ) . '', + ); + ?> +

+

+ ' . esc_html__( 'open an issue on Github', 'wppus' ) . '', + 'wppus-help@anyape.com', + ); + ?> +

+
From 433e6ff57666ccbc41106391a2ffb2b8ecb93a63 Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Fri, 12 Jan 2024 17:39:20 +0800 Subject: [PATCH 4/7] correct typos --- README.md | 2 +- inc/templates/admin/plugin-help-page.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 545b0b4..da18960 100644 --- a/README.md +++ b/README.md @@ -361,7 +361,7 @@ See `wp-content/plugins/wp-packages-update-server/integration/dummy-plugin` for See `wp-content/plugins/wp-packages-update-server/integration/dummy-generic` for examples of a generic package written in Bash, NodeJS, PHP with Curl, and Python. The API calls made by generic packages to the license API and Update API are the same as the WordPress packages. Unlike the upgrade library provided with plugins & themes, the code found in `wppwus-api.[sh|php|js|py]` files is **NOT ready for production environment and MUST be adapted**. -Unless "Use Remote Repository Service" is checked in "Remote Sources", you need to manually upload the packages zip archives (and subsequent updates) in `wp-content/wppus/packages` or `CloudStorageUnit://wppus-packages/`. Packages need to be valid WordPress plugin or theme packages, and in the case of a plugin the main plugin file must have the same name as the zip archive. For example, the main plugin file in `package-slug.zip` would be `package-slug.php`. +Unless "Use Remote Repository Service" is checked in "Remote Sources", you need to manually upload the packages zip archives (and subsequent updates) in `wp-content/wppus/packages` or `CloudStorageUnit://wppus-packages/`. A package needs to a valid generic package, or a valid WordPress plugin or theme package, and in the case of a plugin the main plugin file must have the same name as the zip archive. For example, the main plugin file in `package-slug.zip` would be `package-slug.php`. ### Requests optimisation diff --git a/inc/templates/admin/plugin-help-page.php b/inc/templates/admin/plugin-help-page.php index 6f55140..b4ad64e 100644 --- a/inc/templates/admin/plugin-help-page.php +++ b/inc/templates/admin/plugin-help-page.php @@ -78,7 +78,7 @@ printf( // translators: %1$s is integration/dummy-plugin, %2$s is integration/dummy-theme esc_html__( 'See %1$s for an example of plugin, and %2$ss for an example of theme. They are fully functionnal and can be used to test all the features of the server with a test client installation of WordPress.', 'wppus' ), - '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-plugin', + '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-theme', '' . esc_html( WPPUS_PLUGIN_PATH ) . 'integration/dummy-plugin', ); ?> @@ -97,7 +97,7 @@ packages_dir, %2$s is package-slug.zip, %3$s is package-slug.php - esc_html__( 'Unless "Use Remote Repository Service" is checked in "Remote Sources", you need to manually upload the packages zip archives (and subsequent updates) in %1$s. A packages need to a valid generic package, or a valid WordPress plugin or theme package, and in the case of a plugin the main plugin file must have the same name as the zip archive. For example, the main plugin file in %2$s would be %3$s.', 'wppus' ), + esc_html__( 'Unless "Use Remote Repository Service" is checked in "Remote Sources", you need to manually upload the packages zip archives (and subsequent updates) in %1$s. A package needs to a valid generic package, or a valid WordPress plugin or theme package, and in the case of a plugin the main plugin file must have the same name as the zip archive. For example, the main plugin file in %2$s would be %3$s.', 'wppus' ), '' . esc_html( $packages_dir ) . '', 'package-slug.zip', 'package-slug.php', From 2028239d1595ab5716de1df25ccac80fe829b251 Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Fri, 12 Jan 2024 17:41:35 +0800 Subject: [PATCH 5/7] yoda yoda yoda --- README.md | 2 +- inc/templates/admin/plugin-help-page.php | 2 +- integration/dummy-plugin/dummy-plugin.php | 2 +- .../lib/wp-package-updater/class-wp-package-updater.php | 2 +- integration/dummy-theme/functions.php | 2 +- .../lib/wp-package-updater/class-wp-package-updater.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index da18960..721b169 100644 --- a/README.md +++ b/README.md @@ -341,7 +341,7 @@ require_once __DIR__ . '/lib/wp-package-updater/class-wp-package-updater.php'; $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() + 0 === strpos( __DIR__, WP_PLUGIN_DIR ) ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); ``` - Add a `wppus.json` file at the root of the package with the following content - change the value of `"server"` to your own (required), and select a value for `"requireLicense"` (optional): diff --git a/inc/templates/admin/plugin-help-page.php b/inc/templates/admin/plugin-help-page.php index b4ad64e..36eecfb 100644 --- a/inc/templates/admin/plugin-help-page.php +++ b/inc/templates/admin/plugin-help-page.php @@ -37,7 +37,7 @@ $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() + 0 === strpos( __DIR__, WP_PLUGIN_DIR ) ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() );
  • diff --git a/integration/dummy-plugin/dummy-plugin.php b/integration/dummy-plugin/dummy-plugin.php index 8cb9fad..80c2ed4 100644 --- a/integration/dummy-plugin/dummy-plugin.php +++ b/integration/dummy-plugin/dummy-plugin.php @@ -39,7 +39,7 @@ $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() + 0 === strpos( __DIR__, WP_PLUGIN_DIR ) ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ diff --git a/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php b/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php index a92dc00..4842ed1 100644 --- a/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php +++ b/integration/dummy-plugin/lib/wp-package-updater/class-wp-package-updater.php @@ -38,7 +38,7 @@ $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() + 0 === strpos( __DIR__, WP_PLUGIN_DIR ) ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ diff --git a/integration/dummy-theme/functions.php b/integration/dummy-theme/functions.php index 9461ac7..4f0ce3a 100644 --- a/integration/dummy-theme/functions.php +++ b/integration/dummy-theme/functions.php @@ -27,7 +27,7 @@ $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() + 0 === strpos( __DIR__, WP_PLUGIN_DIR ) ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ diff --git a/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php b/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php index a92dc00..4842ed1 100644 --- a/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php +++ b/integration/dummy-theme/lib/wp-package-updater/class-wp-package-updater.php @@ -38,7 +38,7 @@ $prefix_updater = new WP_Package_Updater( wp_normalize_path( __FILE__ ), - strpos( __DIR__, WP_PLUGIN_DIR ) === 0 ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() + 0 === strpos( __DIR__, WP_PLUGIN_DIR ) ? wp_normalize_path( __DIR__ ) : get_stylesheet_directory() ); */ From 27e2f07ec45679e951c382ad89ea854566448e09 Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Fri, 12 Jan 2024 17:45:58 +0800 Subject: [PATCH 6/7] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 721b169..1df3281 100644 --- a/README.md +++ b/README.md @@ -354,7 +354,7 @@ $prefix_updater = new WP_Package_Updater( - Connect WPPUS with your repository and prime your package, or manually upload your package to WPPUS. For generic packages, the steps involved entirely depend on the language used to write the package and the update process of the target platform. -You may refer to the documentation found [here](https://github.com/froger-me/wp-packages-update-server/blob/main/integration/docs/generic.md) +You may refer to the documentation found [here](https://github.com/froger-me/wp-packages-update-server/blob/main/integration/docs/generic.md). ___ See `wp-content/plugins/wp-packages-update-server/integration/dummy-plugin` for an example of plugin, and `wp-content/plugins/wp-packages-update-server/integration/dummy-theme` for an example of theme. They are fully functionnal and can be used to test all the features of the server with a test client installation of WordPress. From 14567fd3d15f873573cf5cefdc1d9a676599c7ea Mon Sep 17 00:00:00 2001 From: Alexandre Froger Date: Fri, 12 Jan 2024 17:57:12 +0800 Subject: [PATCH 7/7] check if license page before init stuff --- js/admin/license.js | 5 +++++ js/admin/license.min.js | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/js/admin/license.js b/js/admin/license.js index e4e27c5..fb3814c 100644 --- a/js/admin/license.js +++ b/js/admin/license.js @@ -1,5 +1,10 @@ /* global Wppus, console */ jQuery(document).ready(function ($) { + + if ($('.wp-packages-update-server_page_wppus-page-licenses').length === 0) { + return; + } + editor = wp.codeEditor.initialize($('#wppus_license_data'), WppusAdminLicense.cm_settings); $('#add_license_trigger').on('click', function() { diff --git a/js/admin/license.min.js b/js/admin/license.min.js index 2abcc90..ba2f87c 100644 --- a/js/admin/license.min.js +++ b/js/admin/license.min.js @@ -1 +1 @@ -jQuery(document).ready(function(e){function s(s){if(e.isPlainObject(s)){if(e("#wppus_license_id").html(s.id),e("#wppus_license_key").val(s.license_key),e("#wppus_license_date_created").val(s.date_created),e("#wppus_license_max_allowed_domains").val(s.max_allowed_domains),e("#wppus_license_owner_name").val(s.owner_name),e("#wppus_license_registered_email").val(s.email),e("#wppus_license_owner_company").val(s.company_name),e("#wppus_license_transaction_id").val(s.txn_id),e("#wppus_license_package_slug").val(s.package_slug),e("#wppus_license_status").val(s.status),e("#wppus_license_data").val(s.data?JSON.stringify(JSON.parse(s.data),null,"\t"):""),e("#wppus_license_package_type").val(s.package_type),editor.codemirror.setValue(e("#wppus_license_data").val()),"0000-00-00"!==s.date_expiry&&e("#wppus_license_date_expiry").val(s.date_expiry),"0000-00-00"!==s.date_renewed&&e("#wppus_license_date_renewed").val(s.date_renewed),s.allowed_domains.length>0){var a=e(".wppus-domains-list"),i=a.find("li").clone();i.removeClass("wppus-domain-template"),e.each(s.allowed_domains,function(e,s){var n=i.clone();n.find(".wppus-domain-value").html(s),a.append(n)}),e(".wppus-no-domain").hide(),a.show()}}else e("#wppus_license_key").val(e("#wppus_license_key").data("random_key")),e("#wppus_license_date_created").val((new Date).toISOString().slice(0,10)),e("#wppus_license_max_allowed_domains").val(1)}function a(){e("#wppus_license").trigger("reset"),e("wppus_license_values").val(""),e("wppus_license_action").val(""),e(".open-panel").removeAttr("disabled"),e(".wppus-licenses-table .open-panel").show(),e("#wppus_license_id").html(""),e(".wppus-domains-list li:not(.wppus-domain-template)").remove(),e(".wppus-no-domain").show(),e("label.wppus-license-error").hide(),e(".wppus-license-error").removeClass("wppus-license-error"),editor.codemirror.setValue("{}")}function i(e,s){e.is(":visible")||e.slideDown(100,function(){s(e),e.find(".inside").animate({opacity:"1"},150)})}function n(e,s){e.is(":visible")&&e.slideUp(100,function(){e.find(".inside").css({opacity:"0"}),s(e)})}editor=wp.codeEditor.initialize(e("#wppus_license_data"),WppusAdminLicense.cm_settings),e("#add_license_trigger").on("click",function(){i(e("#wppus_license_panel"),function(){s(),e("#wppus_license_action").val("create"),e(".wppus-edit-license-label").hide(),e(".wppus-license-show-if-edit").hide(),e(".wppus-add-license-label").show(),e(".open-panel").attr("disabled","disabled"),e(".wppus-licenses-table .open-panel").hide(),e("html, body").animate({scrollTop:e("#wppus_license_panel").offset().top-e("#wpadminbar").height()-20},500)})}),e(".wppus-licenses-table .open-panel .edit a").on("click",function(a){a.preventDefault();var n=JSON.parse(e(this).closest("tr").find('input[name="license_data[]"]').val());i(e("#wppus_license_panel"),function(){s(n),e("#wppus_license_action").val("update"),e(".wppus-edit-license-label").show(),e(".wppus-license-show-if-edit").show(),e(".wppus-add-license-label").hide(),e(".open-panel").attr("disabled","disabled"),e(".wppus-licenses-table .open-panel").hide(),e("html, body").animate({scrollTop:e("#wppus_license_panel").offset().top-e("#wpadminbar").height()-20},500)})}),e("#wppus_license_cancel, .close-panel.reset").on("click",function(){e("html, body").animate({scrollTop:e(".wppus-wrap").offset().top-e("#wpadminbar").height()-20},150),n(e("#wppus_license_panel"),function(){a()})}),e.validator&&(e.validator.methods.licenseDate=function(e,s){return this.optional(s)||/[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/.test(e)},e.validator.methods.slug=function(e,s){return this.optional(s)||/[a-z0-9-]*/.test(e)},e("#wppus_license").validate({ignore:".CodeMirror *",errorClass:"wppus-license-error",rules:{wppus_license_key:{required:!0},wppus_license_package_slug:{required:!0,slug:!0},wppus_license_registered_email:{required:!0,email:!0},wppus_license_date_created:{required:!0,licenseDate:!0},wppus_license_date_expiry:{licenseDate:!0},wppus_license_date_renewed:{licenseDate:!0},wppus_license_max_allowed_domains:{required:!0}},submitHandler:function(s){var a=e(".wppus-domains-list li:not(.wppus-domain-template) .wppus-domain-value"),i={id:e("#wppus_license_id").html(),license_key:e("#wppus_license_key").val(),max_allowed_domains:e("#wppus_license_max_allowed_domains").val(),allowed_domains:a.map(function(){return e(this).text()}).get(),status:e("#wppus_license_status").val(),owner_name:e("#wppus_license_owner_name").val(),email:e("#wppus_license_registered_email").val(),company_name:e("#wppus_license_owner_company").val(),txn_id:e("#wppus_license_transaction_id").val(),data:e("#wppus_license_data").val(),date_created:e("#wppus_license_date_created").val(),date_renewed:e("#wppus_license_date_renewed").val(),date_expiry:e("#wppus_license_date_expiry").val(),package_slug:e("#wppus_license_package_slug").val(),package_type:e("#wppus_license_package_type").val()};e("#wppus_license_values").val(JSON.stringify(i)),e(".no-submit").removeAttr("name"),s.submit()}})),e("#wppus_license_registered_domains").on("click",".wppus-remove-domain",function(s){s.preventDefault(),e(this).parent().remove(),1>=e(".wppus-remove-domain").length&&e(".wppus-no-domain").show()})}); \ No newline at end of file +jQuery(document).ready(function(e){function s(s){if(e.isPlainObject(s)){if(e("#wppus_license_id").html(s.id),e("#wppus_license_key").val(s.license_key),e("#wppus_license_date_created").val(s.date_created),e("#wppus_license_max_allowed_domains").val(s.max_allowed_domains),e("#wppus_license_owner_name").val(s.owner_name),e("#wppus_license_registered_email").val(s.email),e("#wppus_license_owner_company").val(s.company_name),e("#wppus_license_transaction_id").val(s.txn_id),e("#wppus_license_package_slug").val(s.package_slug),e("#wppus_license_status").val(s.status),e("#wppus_license_data").val(s.data?JSON.stringify(JSON.parse(s.data),null,"\t"):""),e("#wppus_license_package_type").val(s.package_type),editor.codemirror.setValue(e("#wppus_license_data").val()),"0000-00-00"!==s.date_expiry&&e("#wppus_license_date_expiry").val(s.date_expiry),"0000-00-00"!==s.date_renewed&&e("#wppus_license_date_renewed").val(s.date_renewed),s.allowed_domains.length>0){var a=e(".wppus-domains-list"),i=a.find("li").clone();i.removeClass("wppus-domain-template"),e.each(s.allowed_domains,function(e,s){var p=i.clone();p.find(".wppus-domain-value").html(s),a.append(p)}),e(".wppus-no-domain").hide(),a.show()}}else e("#wppus_license_key").val(e("#wppus_license_key").data("random_key")),e("#wppus_license_date_created").val((new Date).toISOString().slice(0,10)),e("#wppus_license_max_allowed_domains").val(1)}function a(){e("#wppus_license").trigger("reset"),e("wppus_license_values").val(""),e("wppus_license_action").val(""),e(".open-panel").removeAttr("disabled"),e(".wppus-licenses-table .open-panel").show(),e("#wppus_license_id").html(""),e(".wppus-domains-list li:not(.wppus-domain-template)").remove(),e(".wppus-no-domain").show(),e("label.wppus-license-error").hide(),e(".wppus-license-error").removeClass("wppus-license-error"),editor.codemirror.setValue("{}")}function i(e,s){e.is(":visible")||e.slideDown(100,function(){s(e),e.find(".inside").animate({opacity:"1"},150)})}function p(e,s){e.is(":visible")&&e.slideUp(100,function(){e.find(".inside").css({opacity:"0"}),s(e)})}0!==e(".wp-packages-update-server_page_wppus-page-licenses").length&&(editor=wp.codeEditor.initialize(e("#wppus_license_data"),WppusAdminLicense.cm_settings),e("#add_license_trigger").on("click",function(){i(e("#wppus_license_panel"),function(){s(),e("#wppus_license_action").val("create"),e(".wppus-edit-license-label").hide(),e(".wppus-license-show-if-edit").hide(),e(".wppus-add-license-label").show(),e(".open-panel").attr("disabled","disabled"),e(".wppus-licenses-table .open-panel").hide(),e("html, body").animate({scrollTop:e("#wppus_license_panel").offset().top-e("#wpadminbar").height()-20},500)})}),e(".wppus-licenses-table .open-panel .edit a").on("click",function(a){a.preventDefault();var p=JSON.parse(e(this).closest("tr").find('input[name="license_data[]"]').val());i(e("#wppus_license_panel"),function(){s(p),e("#wppus_license_action").val("update"),e(".wppus-edit-license-label").show(),e(".wppus-license-show-if-edit").show(),e(".wppus-add-license-label").hide(),e(".open-panel").attr("disabled","disabled"),e(".wppus-licenses-table .open-panel").hide(),e("html, body").animate({scrollTop:e("#wppus_license_panel").offset().top-e("#wpadminbar").height()-20},500)})}),e("#wppus_license_cancel, .close-panel.reset").on("click",function(){e("html, body").animate({scrollTop:e(".wppus-wrap").offset().top-e("#wpadminbar").height()-20},150),p(e("#wppus_license_panel"),function(){a()})}),e.validator&&(e.validator.methods.licenseDate=function(e,s){return this.optional(s)||/[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])/.test(e)},e.validator.methods.slug=function(e,s){return this.optional(s)||/[a-z0-9-]*/.test(e)},e("#wppus_license").validate({ignore:".CodeMirror *",errorClass:"wppus-license-error",rules:{wppus_license_key:{required:!0},wppus_license_package_slug:{required:!0,slug:!0},wppus_license_registered_email:{required:!0,email:!0},wppus_license_date_created:{required:!0,licenseDate:!0},wppus_license_date_expiry:{licenseDate:!0},wppus_license_date_renewed:{licenseDate:!0},wppus_license_max_allowed_domains:{required:!0}},submitHandler:function(s){var a=e(".wppus-domains-list li:not(.wppus-domain-template) .wppus-domain-value"),i={id:e("#wppus_license_id").html(),license_key:e("#wppus_license_key").val(),max_allowed_domains:e("#wppus_license_max_allowed_domains").val(),allowed_domains:a.map(function(){return e(this).text()}).get(),status:e("#wppus_license_status").val(),owner_name:e("#wppus_license_owner_name").val(),email:e("#wppus_license_registered_email").val(),company_name:e("#wppus_license_owner_company").val(),txn_id:e("#wppus_license_transaction_id").val(),data:e("#wppus_license_data").val(),date_created:e("#wppus_license_date_created").val(),date_renewed:e("#wppus_license_date_renewed").val(),date_expiry:e("#wppus_license_date_expiry").val(),package_slug:e("#wppus_license_package_slug").val(),package_type:e("#wppus_license_package_type").val()};e("#wppus_license_values").val(JSON.stringify(i)),e(".no-submit").removeAttr("name"),s.submit()}})),e("#wppus_license_registered_domains").on("click",".wppus-remove-domain",function(s){s.preventDefault(),e(this).parent().remove(),1>=e(".wppus-remove-domain").length&&e(".wppus-no-domain").show()}))}); \ No newline at end of file